Merge pull request #7 from Dadido3/docker
Some checks failed
golangci-lint / lint (push) Successful in 19s
test / test non-docker (1.23.x, 0.12.0) (push) Failing after 3s
test / test non-docker (1.23.x, 0.13.0) (push) Failing after 4s
test / test non-docker (1.23.x, 0.13.1) (push) Failing after 3s
test / test non-docker (1.23.x, 0.14.0) (push) Failing after 4s
test / test docker (1.23.x, ) (push) Failing after 17s
test / test docker (1.23.x, ghcr.io/typst/typst:0.14.0) (push) Failing after 17s
test / test docker (1.23.x, ghcr.io/typst/typst:v0.12.0) (push) Failing after 17s
test / test docker (1.23.x, ghcr.io/typst/typst:v0.13.0) (push) Failing after 17s
test / test docker (1.23.x, ghcr.io/typst/typst:v0.13.1) (push) Failing after 17s

Add DockerExec caller & Add custom Docker CLI options
This commit is contained in:
David Vogel 2025-11-17 17:05:02 +01:00 committed by GitHub
commit 66b52699b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 383 additions and 16 deletions

View File

@ -124,9 +124,24 @@ typstCaller := typst.Docker{
err := typstCaller.Compile(input, output, &typst.OptionsCompile{FontPaths: []string{"/fonts"}})
```
### Named Docker containers
If you have an already running Docker container that you want to (re)use, you can use `typst.DockerExec` to invoke the Typst executable inside any running container by its name:
```go
typstCaller := typst.DockerExec{
ContainerName: "typst",
}
err := typstCaller.Compile(input, output, options)
```
This method has a lower latency than using `typst.Docker`, as it doesn't need to spin up a Docker container every call.
But you need to manage the lifetime of the Container yourself, or use a Docker orchestrator.
## Caller interface
`typst.CLI` and `typst.Docker` both implement the `typst.Caller` interface.
`typst.CLI`, `typst.Docker` and `typst.DockerExec` implement the `typst.Caller` interface.
## Examples

160
docker-exec.go Normal file
View File

@ -0,0 +1,160 @@
// Copyright (c) 2025 David Vogel
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
package typst
import (
"bufio"
"bytes"
"fmt"
"io"
"os/exec"
)
// Theoretically it's possible to use the Docker SDK directly:
// https://docs.docker.com/reference/api/engine/sdk/examples/
// But that dependency is unnecessarily huge, therefore we will just call the Docker executable.
// DockerExec allows you to invoke Typst commands in a running Docker container.
//
// This uses docker exec, and therefore needs you to set up a running container beforehand.
// For a less complex setup see typst.Docker.
type DockerExec struct {
ContainerName string // The name of the running container you want to invoke Typst in.
TypstPath string // The path to the Typst executable inside of the container. Defaults to `typst` if left empty.
// Custom "docker exec" command line options go here.
// For all available options, see: https://docs.docker.com/reference/cli/docker/container/exec/
//
// Example:
// typst.DockerExec{Custom: []string{"--user", "1000"}} // Use a non-root user inside the docker container.
Custom []string
}
// Ensure that DockerExec implements the Caller interface.
var _ Caller = DockerExec{}
// args returns docker related arguments.
func (d DockerExec) args() ([]string, error) {
if d.ContainerName == "" {
return nil, fmt.Errorf("the provided ContainerName field is empty")
}
typstPath := "typst"
if d.TypstPath != "" {
typstPath = d.TypstPath
}
// Argument -i is needed for stdio to work.
args := []string{"exec", "-i"}
args = append(args, d.Custom...)
args = append(args, d.ContainerName, typstPath)
return args, nil
}
// VersionString returns the Typst version as a string.
func (d DockerExec) VersionString() (string, error) {
args, err := d.args()
if err != nil {
return "", err
}
args = append(args, "--version")
cmd := exec.Command("docker", args...)
var output, errBuffer bytes.Buffer
cmd.Stdout = &output
cmd.Stderr = &errBuffer
if err := cmd.Run(); err != nil {
switch err := err.(type) {
case *exec.ExitError:
return "", ParseStderr(errBuffer.String(), err)
default:
return "", err
}
}
return output.String(), nil
}
// Fonts returns all fonts that are available to Typst.
// The options parameter is optional, and can be nil.
func (d DockerExec) Fonts(options *OptionsFonts) ([]string, error) {
args, err := d.args()
if err != nil {
return nil, err
}
if options == nil {
options = new(OptionsFonts)
}
args = append(args, options.Args()...)
cmd := exec.Command("docker", args...)
var output, errBuffer bytes.Buffer
cmd.Stdout = &output
cmd.Stderr = &errBuffer
if err := cmd.Run(); err != nil {
switch err := err.(type) {
case *exec.ExitError:
return nil, ParseStderr(errBuffer.String(), err)
default:
return nil, err
}
}
var result []string
scanner := bufio.NewScanner(&output)
for scanner.Scan() {
result = append(result, scanner.Text())
}
return result, nil
}
// Compile takes a Typst document from input, and renders it into the output writer.
// The options parameter is optional, and can be nil.
func (d DockerExec) Compile(input io.Reader, output io.Writer, options *OptionsCompile) error {
args, err := d.args()
if err != nil {
return err
}
if options == nil {
options = new(OptionsCompile)
}
args = append(args, options.Args()...)
cmd := exec.Command("docker", args...)
cmd.Stdin = input
cmd.Stdout = output
errBuffer := bytes.Buffer{}
cmd.Stderr = &errBuffer
if err := cmd.Run(); err != nil {
switch err := err.(type) {
case *exec.ExitError:
if err.ExitCode() >= 125 {
// Most likely docker related error.
// TODO: Find a better way to distinguish between Typst or Docker errors.
return fmt.Errorf("exit code %d: %s", err.ExitCode(), errBuffer.String())
} else {
// Typst related error.
return ParseStderr(errBuffer.String(), err)
}
default:
return err
}
}
return nil
}

184
docker-exec_test.go Normal file
View File

@ -0,0 +1,184 @@
// Copyright (c) 2025 David Vogel
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
package typst_test
import (
"bytes"
"image"
"os/exec"
"strconv"
"testing"
"github.com/Dadido3/go-typst"
)
func TestDockerExec(t *testing.T) {
// Just to ensure that there is no container running.
exec.Command("docker", "stop", "-t", "1", "typst-instance").Run() //nolint:errcheck
exec.Command("docker", "rm", "typst-instance").Run() //nolint:errcheck
if err := exec.Command("docker", "run", "--name", "typst-instance", "-v", "./test-files:/test-files", "-id", "123marvin123/typst").Run(); err != nil {
t.Fatalf("Failed to run Docker container: %v.", err)
}
t.Cleanup(func() {
exec.Command("docker", "stop", "-t", "1", "typst-instance").Run() //nolint:errcheck
exec.Command("docker", "rm", "typst-instance").Run() //nolint:errcheck
})
tests := []struct {
Name string
Function func(*testing.T)
}{
{"VersionString", dockerExec_VersionString},
{"Fonts", dockerExec_Fonts},
{"FontsWithOptions", dockerExec_FontsWithOptions},
{"FontsWithFontPaths", dockerExec_FontsWithFontPaths},
{"Compile", dockerExec_Compile},
{"CompileWithWorkingDir", dockerExec_CompileWithWorkingDir},
}
for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
t.Parallel()
test.Function(t)
})
}
}
func dockerExec_VersionString(t *testing.T) {
typstCaller := typst.DockerExec{
ContainerName: "typst-instance",
}
v, err := typstCaller.VersionString()
if err != nil {
t.Fatalf("Failed to get typst version: %v.", err)
}
t.Logf("VersionString: %s", v)
}
func dockerExec_Fonts(t *testing.T) {
typstCaller := typst.DockerExec{
ContainerName: "typst-instance",
}
result, err := typstCaller.Fonts(nil)
if err != nil {
t.Fatalf("Failed to get available fonts: %v.", err)
}
if len(result) < 4 {
t.Errorf("Unexpected number of detected fonts. Got %d, want >= %d.", len(result), 4)
}
}
func dockerExec_FontsWithOptions(t *testing.T) {
typstCaller := typst.DockerExec{
ContainerName: "typst-instance",
}
result, err := typstCaller.Fonts(&typst.OptionsFonts{IgnoreSystemFonts: true})
if err != nil {
t.Fatalf("Failed to get available fonts: %v.", err)
}
if len(result) != 4 {
t.Errorf("Unexpected number of detected fonts. Got %d, want %d.", len(result), 4)
}
}
func dockerExec_FontsWithFontPaths(t *testing.T) {
typstCaller := typst.DockerExec{
ContainerName: "typst-instance",
}
result, err := typstCaller.Fonts(&typst.OptionsFonts{IgnoreSystemFonts: true, FontPaths: []string{"/test-files"}})
if err != nil {
t.Fatalf("Failed to get available fonts: %v.", err)
}
if len(result) != 5 {
t.Errorf("Unexpected number of detected fonts. Got %d, want %d.", len(result), 5)
}
}
// Test basic compile functionality.
func dockerExec_Compile(t *testing.T) {
const inches = 1
const ppi = 144
typstCaller := typst.DockerExec{
ContainerName: "typst-instance",
}
r := bytes.NewBufferString(`#set page(width: ` + strconv.FormatInt(inches, 10) + `in, height: ` + strconv.FormatInt(inches, 10) + `in, margin: (x: 1mm, y: 1mm))
= Test
#lorem(5)`)
opts := typst.OptionsCompile{
Format: typst.OutputFormatPNG,
PPI: ppi,
}
var w bytes.Buffer
if err := typstCaller.Compile(r, &w, &opts); err != nil {
t.Fatalf("Failed to compile document: %v.", err)
}
imgConf, imgType, err := image.DecodeConfig(&w)
if err != nil {
t.Fatalf("Failed to decode image: %v.", err)
}
if imgType != "png" {
t.Fatalf("Resulting image is of type %q, expected %q.", imgType, "png")
}
if imgConf.Width != inches*ppi {
t.Fatalf("Resulting image width is %d, expected %d.", imgConf.Width, inches*ppi)
}
if imgConf.Height != inches*ppi {
t.Fatalf("Resulting image height is %d, expected %d.", imgConf.Height, inches*ppi)
}
}
// Test basic compile functionality with a given working directory.
func dockerExec_CompileWithWorkingDir(t *testing.T) {
typstCaller := typst.DockerExec{
ContainerName: "typst-instance",
}
r := bytes.NewBufferString(`#import "hello-world-template.typ": template
#show: doc => template()`)
var w bytes.Buffer
err := typstCaller.Compile(r, &w, &typst.OptionsCompile{Root: "/test-files"})
if err != nil {
t.Fatalf("Failed to compile document: %v.", err)
}
if w.Available() == 0 {
t.Errorf("No output was written.")
}
}
func TestDockerExec_EmptyContainerName(t *testing.T) {
typstCaller := typst.DockerExec{
ContainerName: "",
}
_, err := typstCaller.VersionString()
if err == nil {
t.Errorf("Expected error, but got nil.")
}
}
func TestDockerExec_NonRunningContainer(t *testing.T) {
typstCaller := typst.DockerExec{
ContainerName: "something-else",
}
_, err := typstCaller.VersionString()
if err == nil {
t.Errorf("Expected error, but got nil.")
}
}

View File

@ -22,6 +22,10 @@ import (
const DockerDefaultImage = "ghcr.io/typst/typst:0.14.0"
// Docker allows you to invoke commands on a Typst Docker image.
//
// This uses docker run to automatically pull and run a container.
// Therefore the container will start and stop automatically.
// To have more control over the lifetime of a Docker container see typst.DockerExec.
type Docker struct {
Image string // The image to use, defaults to the latest supported offical Typst Docker image if left empty. See: typst.DockerDefaultImage.
WorkingDirectory string // The working directory of Docker. When left empty, Docker will be run with the process's current working directory.
@ -33,6 +37,13 @@ type Docker struct {
// typst.Docker{Volumes: []string{".:/markup"}} // This bind mounts the current working directory to "/markup" inside the container.
// typst.Docker{Volumes: []string{"/usr/share/fonts:/usr/share/fonts"}} // This makes all system fonts available to Typst running inside the container.
Volumes []string
// Custom "docker run" command line options go here.
// For all available options, see: https://docs.docker.com/reference/cli/docker/container/run/
//
// Example:
// typst.Docker{Custom: []string{"--user", "1000"}} // Use a non-root user inside the docker container.
Custom []string // Custom "docker run" command line options go here.
}
// Ensure that Docker implements the Caller interface.
@ -48,6 +59,8 @@ func (d Docker) args() []string {
// Argument -i is needed for stdio to work.
args := []string{"run", "-i"}
args = append(args, d.Custom...)
// Add mounts.
for _, volume := range d.Volumes {
args = append(args, "-v", volume)
@ -120,8 +133,6 @@ func (d Docker) Fonts(options *OptionsFonts) ([]string, error) {
func (d Docker) Compile(input io.Reader, output io.Writer, options *OptionsCompile) error {
args := d.args()
// From here on come Typst arguments.
if options == nil {
options = new(OptionsCompile)
}

View File

@ -33,7 +33,7 @@
<use xlink:href="#gCBEB678AF171DD94ACB89CCECEB5D533" x="149.22600000000003" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#gD58EEB85C3CF258DFE9908E9C6F904D4" x="154.34100000000004" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#gCBEB678AF171DD94ACB89CCECEB5D533" x="158.05900000000003" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g1E4752F03A1A865A0DBDFDB7CB983A33" x="163.17400000000004" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#gC3007A8C442F339190FF56DBF550BEA" x="163.17400000000004" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g653D6F5329F61DB2D83AF3CFD189F307" x="171.03900000000004" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g51B05C4190BD85788EF3601873C2936A" x="176.06600000000003" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g49431E85F668A3E0C612B4AA9C4D5CE8" x="182.02800000000002" y="0" fill="#000000" fill-rule="nonzero"/>
@ -49,13 +49,13 @@
</g>
<g class="typst-text" transform="matrix(1 0 0 -1 14.173228346456693 35.799228346456694)">
<use xlink:href="#gCBEB678AF171DD94ACB89CCECEB5D533" x="0" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g20CA0FB04A6BED1E0C44BC156D3D12C5" x="5.115" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g85D7D3DA5193E73F6C733369948756C2" x="5.115" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g5433311E1B7F4B245320FED5B7100250" x="10.23" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g85D7D3DA5193E73F6C733369948756C2" x="12.826" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g20CA0FB04A6BED1E0C44BC156D3D12C5" x="17.941000000000003" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g6A93160A3C7E07C6D055C9F6C1746C6A" x="12.826" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#gCBEB678AF171DD94ACB89CCECEB5D533" x="17.941000000000003" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g5433311E1B7F4B245320FED5B7100250" x="23.056000000000004" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g179D92325684FA5055722CBA7015DA1A" x="25.652000000000005" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g6A93160A3C7E07C6D055C9F6C1746C6A" x="30.767000000000003" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g6A93160A3C7E07C6D055C9F6C1746C6A" x="25.652000000000005" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#g17FCF64AFC48E81F707D872D7D9D0570" x="30.767000000000003" y="0" fill="#000000" fill-rule="nonzero"/>
<use xlink:href="#gB119B92F4F4BA43398207C44B71084FA" x="35.882000000000005" y="0" fill="#000000" fill-rule="nonzero"/>
</g>
<g class="typst-text" transform="matrix(1 0 0 -1 14.173228346456693 55.68516584645669)">
@ -222,8 +222,8 @@
<symbol id="gCBEB678AF171DD94ACB89CCECEB5D533" overflow="visible">
<path d="M 0 0m 3.168 1.342 v 3.817 c 0 0.65999985 0.010999918 1.3309999 0.032999992 1.474 c 0 0.05499983 -0.022000074 0.05499983 -0.065999985 0.05499983 c -0.605 -0.3739996 -1.188 -0.6489997 -2.1560001 -1.0999999 c 0.022000074 -0.12099981 0.065999985 -0.23099995 0.16500008 -0.29699993 c 0.5059999 0.20900011 0.7479999 0.2750001 0.957 0.2750001 c 0.18700004 0 0.22000003 -0.26399994 0.22000003 -0.638 v -3.586 c 0 -0.913 -0.29700017 -0.968 -1.0670002 -1.001 c -0.065999985 -0.065999985 -0.065999985 -0.297 0 -0.36299998 c 0.53900003 0.011 0.93499994 0.022 1.529 0.022 c 0.5279999 0 0.79200006 -0.011 1.342 -0.022 c 0.065999985 0.066 0.065999985 0.297 0 0.36299998 c -0.77 0.033000022 -0.957 0.088 -0.957 1.001 Z "/>
</symbol>
<symbol id="g1E4752F03A1A865A0DBDFDB7CB983A33" overflow="visible">
<path d="M 0 0m 1.584 3.773 c 0.29700005 1.0010002 1.001 2.1119998 2.4639997 2.662 c 0 0.13199997 -0.043999672 0.23099995 -0.13199997 0.28600025 c -1.1109998 -0.3300004 -1.793 -0.7920003 -2.409 -1.5070004 c -0.682 -0.7919998 -1.023 -1.7929997 -1.023 -2.6619997 c 0 -2.233 1.265 -2.673 2.112 -2.673 c 1.4410002 0 2.035 1.3970001 2.035 2.343 c 0 0.9460001 -0.50600004 1.793 -2.002 1.793 c -0.286 0 -0.7149999 -0.08799982 -1.045 -0.24199986 Z m -0.09899998 -0.3959999 c 0.36300004 0.24199986 0.72599995 0.25299978 0.913 0.25299978 c 1.0780001 0 1.3199999 -1.056 1.3199999 -1.606 c 0 -1.2099999 -0.4619999 -1.76 -1.0009999 -1.76 c -0.6930001 0 -1.32 0.374 -1.32 2.255 c 0 0.25300002 0.022000074 0.53900003 0.08800006 0.85800004 Z "/>
<symbol id="gC3007A8C442F339190FF56DBF550BEA" overflow="visible">
<path d="M 0 0m 1.87 5.8849998 h 1.969 c -0.85800004 -2.1339998 -1.727 -4.279 -2.475 -5.9509997 l 0.08800006 -0.07700001 l 0.748 0.033000007 c 0.62699986 1.87 1.2319999 3.6959999 2.464 6.699 l -0.17600012 0.13200045 c -0.1869998 -0.055000305 -0.4289999 -0.12100029 -0.8469999 -0.12100029 h -2.266 c -0.37399995 0 -0.352 0.11000013 -0.55 0.15400028 c -0.032999992 0 -0.04399997 0 -0.04399997 -0.032999992 c -0.011000037 -0.52800035 -0.13200003 -1.1880002 -0.22000003 -1.7600002 c 0.12099999 -0.032999992 0.231 -0.04400015 0.352 -0.032999992 c 0.24199998 0.8800001 0.605 0.9569998 0.957 0.9569998 Z "/>
</symbol>
<symbol id="g51B05C4190BD85788EF3601873C2936A" overflow="visible">
<path d="M 0 0m 2.024 3.938 c -0.065999985 -0.0769999 -0.13199997 -0.09899998 -0.13199997 0 c -0.010999918 0.29700017 -0.032999992 0.7260001 -0.08799994 0.8360002 c -0.022000074 0.05499983 -0.04400003 0.08799982 -0.13200009 0.08799982 c -0.30799997 -0.12099981 -0.594 -0.21999979 -1.3529999 -0.31900024 c -0.022000015 -0.065999985 0 -0.24199963 0.021999985 -0.3079996 c 0.594 -0.055000305 0.71500003 -0.11000013 0.71500003 -0.74800014 v -2.145 c 0 -0.902 -0.110000014 -0.946 -0.77 -1.001 c -0.066000015 -0.065999985 -0.066000015 -0.297 0 -0.36299998 c 0.32999998 0.011 0.77 0.022 1.21 0.022 c 0.43999994 0 0.77 -0.011 1.0999999 -0.022 c 0.065999985 0.066 0.065999985 0.297 0 0.36299998 c -0.5609999 0.055000007 -0.671 0.09900001 -0.671 1.001 v 1.8039999 c 0 0.23100019 0.09899998 0.36300015 0.18700004 0.46200013 c 0.41799998 0.40699983 0.9130001 0.6489999 1.342 0.6489999 c 0.22000003 0 0.45099998 -0.14300013 0.5830002 -0.3959999 c 0.10999966 -0.22000003 0.13199997 -0.5170002 0.13199997 -0.8470001 v -1.6719999 c 0 -0.902 -0.11000013 -0.946 -0.68200016 -1.001 c -0.055000067 -0.065999985 -0.055000067 -0.297 0 -0.36299998 c 0.32999992 0.011 0.68200016 0.022 1.1220002 0.022 c 0.43999958 0 0.83599997 -0.011 1.1659999 -0.022 c 0.05499983 0.066 0.05499983 0.297 0 0.36299998 c -0.6160002 0.055000007 -0.737 0.09900001 -0.737 1.001 v 1.6389999 c 0 0.605 -0.04400015 1.1329999 -0.29699993 1.474 c -0.18700027 0.2420001 -0.52800035 0.37400007 -0.9130001 0.37400007 c -0.53900003 0 -1.155 -0.14300013 -1.8040001 -0.89100003 Z "/>
@ -231,9 +231,6 @@
<symbol id="gD0BE2DBF7243AF20ECD6B66E738F95D2" overflow="visible">
<path d="M 0 0m 1.87 3.938 c -0.011000037 0.33000016 -0.032999992 0.7260001 -0.08800006 0.8360002 c -0.021999955 0.05499983 -0.04399991 0.08799982 -0.13199997 0.08799982 c -0.30799997 -0.12099981 -0.594 -0.21999979 -1.3529999 -0.31900024 c -0.021999985 -0.065999985 0 -0.24199963 0.022000015 -0.3079996 c 0.594 -0.055000305 0.71500003 -0.11000013 0.71500003 -0.74800014 v -2.145 c 0 -0.902 -0.14300007 -0.957 -0.748 -1.001 c -0.066000015 -0.065999985 -0.066000015 -0.297 0 -0.36299998 c 0.32999998 0.011 0.748 0.022 1.188 0.022 c 0.44000006 0 0.7809999 -0.011 1.1110001 -0.022 c 0.065999985 0.066 0.065999985 0.297 0 0.36299998 c -0.5610001 0.055000007 -0.68200004 0.09900001 -0.68200004 1.001 v 1.8039999 c 0 0.23100019 0.0990001 0.36300015 0.18699992 0.46200013 c 0.44000006 0.42900014 0.8470001 0.6489999 1.188 0.6489999 c 0.41800022 0 0.7260003 -0.26399994 0.7260003 -1.0009999 v -1.914 c 0 -0.902 -0.0880003 -0.957 -0.68200016 -1.001 c -0.055000067 -0.065999985 -0.055000067 -0.297 0 -0.36299998 c 0.27499986 0.011 0.68200016 0.022 1.1219997 0.022 c 0.44000006 0 0.803 -0.011 1.0780001 -0.022 c 0.055000305 0.066 0.055000305 0.297 0 0.36299998 c -0.5499997 0.044 -0.6489997 0.09900001 -0.6489997 1.001 v 1.7490001 c 0 0.1539998 0 0.30799985 -0.011000156 0.43999982 c 0.5279999 0.58299994 1.0229998 0.7260001 1.4520001 0.7260001 c 0.41799974 0 0.65999985 -0.2420001 0.65999985 -0.9790001 v -1.9359999 c 0 -0.902 -0.11000013 -0.957 -0.68200016 -1.001 c -0.05499983 -0.065999985 -0.05499983 -0.297 0 -0.36299998 c 0.2750001 0.011 0.68200016 0.022 1.1220002 0.022 c 0.44000006 0 0.8250003 -0.011 1.1329999 -0.022 c 0.055000305 0.066 0.055000305 0.297 0 0.36299998 c -0.605 0.044 -0.704 0.09900001 -0.704 1.001 v 1.7379999 c 0 0.9790001 -0.16499996 1.7490001 -1.1329999 1.7490001 c -0.5609999 0 -1.243 -0.20900011 -1.815 -0.8140001 c -0.032999992 -0.032999992 -0.09899998 -0.08799982 -0.12099981 0.011000156 c -0.09899998 0.45099974 -0.52800035 0.803 -1.1000001 0.803 c -0.638 0 -1.21 -0.37400007 -1.6719999 -0.89100003 c -0.055000067 -0.055000067 -0.12100005 -0.13199997 -0.13200009 0 Z "/>
</symbol>
<symbol id="g20CA0FB04A6BED1E0C44BC156D3D12C5" overflow="visible">
<path d="M 0 0m 4.323 5.335 c 0 0.7919998 -0.61599994 1.375 -1.694 1.375 c -1.122 0 -1.8479999 -0.671 -1.8479999 -1.5180001 c 0 -0.6159997 0.29699993 -1.0669999 0.96799994 -1.4849999 l 0.28600013 -0.17600012 c -0.31900012 -0.16499996 -0.61600006 -0.36299992 -0.89100003 -0.605 c -0.45100003 -0.3959999 -0.6380001 -0.8909998 -0.6380001 -1.3199999 c 0 -1.122 0.792 -1.716 1.958 -1.716 c 1.441 0 2.1450002 1.056 2.1450002 1.892 c 0 0.63800013 -0.2750001 1.199 -0.8580003 1.551 l -0.7809999 0.47300005 c 0.51699996 0.25300002 1.3529999 0.82500005 1.3529999 1.529 Z m -1.8369999 -5.06 c -0.49500012 0 -1.243 0.341 -1.243 1.331 c 0 0.33000004 0.143 1.1000001 1.089 1.727 l 0.51699996 -0.30799985 c 0.6819999 -0.41800022 0.957 -0.9350002 0.957 -1.463 c 0 -1.1 -0.82500005 -1.2870001 -1.3199999 -1.2870001 Z m 0.08799982 6.0499997 c 0.71500015 0 0.9790001 -0.47300005 0.9790001 -0.9789996 c 0 -0.59400034 -0.58299994 -1.0890002 -0.8799999 -1.309 l -0.34100008 0.20899963 c -0.6930001 0.4510002 -0.77 0.8140001 -0.77 1.1550002 c 0 0.50600004 0.352 0.9239998 1.0119998 0.9239998 Z "/>
</symbol>
<symbol id="g5433311E1B7F4B245320FED5B7100250" overflow="visible">
<path d="M 0 0m 0.77 0.65999997 c 0 -0.31899998 0.26400006 -0.58299994 0.58300006 -0.58299994 c 0.3189999 0 0.58299994 0.264 0.58299994 0.58299994 c 0 0.319 -0.26400006 0.58300006 -0.58299994 0.58300006 c -0.319 0 -0.58300006 -0.26400006 -0.58300006 -0.58300006 Z m 0 3.2779999 c 0 -0.319 0.26400006 -0.58299994 0.58300006 -0.58299994 c 0.3189999 0 0.58299994 0.26399994 0.58299994 0.58299994 c 0 0.319 -0.26400006 0.58299994 -0.58299994 0.58299994 c -0.319 0 -0.58300006 -0.26399994 -0.58300006 -0.58299994 Z "/>
</symbol>

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -83,7 +83,7 @@ func TestREADME6(t *testing.T) {
}
}
func TestREADME7(t *testing.T) {
func TestREADME8(t *testing.T) {
markup := bytes.NewBufferString(`#set page(width: 100mm, height: auto, margin: 5mm)
= go-typst
@ -110,7 +110,7 @@ A library to generate documents and reports by utilizing the command line versio
}
}
func TestREADME8(t *testing.T) {
func TestREADME9(t *testing.T) {
customValues := map[string]any{
"time": time.Now(),
"customText": "Hey there!",