4

Background

Developers (and pipelines) check out a repository into a local environment, or container, as follows:

git clone https://hostname/repositories/project

This project contains fonts, images, and documents ready for typesetting. We'd like to typeset by passing the font directory into ConTeXt via the command-line, such as:

mtxrun --arguments=fontsdir=/path/to/project/fonts

Every developer has a different path to the fonts directory (e.g., $HOME/repos/project/fonts) because we don't control the repository's clone path.

Environment

mtx-context     | current version: 2025.04.28 14:29

Problem

The issue is that the fonts, after being checked out from the repository, aren't being picked up by ConTeXt. This makes sense because we haven't told it where to find the fonts, which can be found relative to the project's root directory.

While we could tell the developers to update OSFONTDIR and run mtxrun --script fonts --reload, it's a bit cumbersome. Preferably, the path could be passed in:

mtxrun --arguments=fontsdir=$HOME/repos/project/fonts

Code

What we want is to run the following code (or similar) before typesetting starts:

\ctxlua{
  os.setenv(
    "RUNTIMEFONTS",
    context( "\env{fontsdir}" )
  )
}

This is just one idea. The result of running that code is the path to the fonts directory is typeset into the document. That tells us the path is correct, but it also means that the RUNTIMEFONTS value isn't set.

Even hard-coding the path, in place of calling context(...) doesn't work, so setting the RUNTIMEFONTS variable is not feasible.

Ideas

Environment variables

We updated the Makefile to set the environment variables, but requires running mtxrun twice (once with --generate; using --autogenerate doesn't work to autodetect the cache directory), such as:

guide:
  command -v mtxrun || { echo "Install ConTeXt"; exit 1; }

  TEXMFCACHE="/tmp" OSFONTDIR="$(THEME_DIR)/fonts//" \
  mtxrun --generate

  TEXMFCACHE="/tmp" OSFONTDIR="$(THEME_DIR)/fonts//" \
  mtxrun --autogenerate ...

This allows make guide without having to pass environment variables to make.

\usefontpath

We modified "setups.tex" (the main entry point for our documentation's .tex files) with the following line:

\doifdocumentargument{fontsdir{%
  \usefontpath[\getdocumentargument{fontsdir}]
}

And added fontsdir to specify the fully qualified path to the fonts directory:

mtxrun \
 --autogenerate \
 --script mtx-context \
 --batchmode \
 --nonstopmode \
 --purgeall \
 --environment=main \
 --arguments=fontsdir=/path/to/fonts

The fonts did not get used, likely because getdocumentargument{fontsdir} is returning an empty string:

  \startdocument
    FONTDIR:\getdocumentargument{fontsdir}

    % ... etc.    
  \stopdocument

Using \usefontpath[\env{fontsdir}] did not work to find the files, despite \env{fontsdir} being a valid and fully qualified directory containing the font files.

Question

What is the best way to dynamically set a font directory at runtime using ConTeXt? (Recursively would be ideal, but all the fonts are in a flat directory structure, so recursion isn't needed for our purposes.)

7
  • 1
    ConTeXt provides the command \usefontpath to add local font files. To set a directory on the command line you can add \doifdocumentargument{fontsdir}{\usefontpath[\getdocumentargument{fontsdir}]} to the document style. Commented Jul 16 at 21:02
  • \getdocumentargument{fontsdir} is empty; \env{fontsdir} provides the correct directory. Adding \usefontpath[\env{fontsdir}] to the main .tex file failed to find the font files. Commented Jul 16 at 21:29
  • To set a value used with \getdocumentargument you have to use context --fontsdir=.... Commented Jul 16 at 22:02
  • I don't know how context works. does it require remaking the formats to use fonts found in TEXMFHOME, for example? I guess I could test ... Commented Jul 17 at 0:12
  • 1
    The suggestion by @WolfgangSchuster works (of course) well. One has to be a bit careful with caching, though, if one uses the fonts from several locations (then just remove the corresponding .tma and .tmd files). (It is also possible to set the environment variable RUNTIMEFONTS directly for the run. This is explained in the documentation, more precicely in fonts-formats.tex) Commented Jul 17 at 15:02

1 Answer 1

2

What is the best way to dynamically set a font directory at runtime using ConTeXt?

I don't know about the best way, but using the following Lua code seems to work:

os.setenv("OSFONTDIR", document.getargument("fontsdir")

To test this, I downloaded a random font that I've never used before from Google Fonts, and the compiled the following document:

\startluacode
    table.merge(
        document.arguments,
        utilities.parsers.settings_to_hash(document.getargument("arguments", ""))
    )

    os.setenv("OSFONTDIR",
        table.concat({
            document.getargument("fontsdir", ""),
            "/an/optional/hardcoded/path/",
            os.getenv("OSFONTDIR") or "",
        }, ":")
    )
\stopluacode

\startTEXpage[offset=1ex]
    \definedfont[BitcountGridDouble-Regular.ttf*default]
    Hello, \ConTeXt!
\stopTEXpage

using the following command:

$ ls ./BitcountGridDouble-Regular.ttf
ls: cannot access './BitcountGridDouble-Regular.ttf': No such file or directory

$ ls /tmp/a-random-folder/
BitcountGridDouble-Regular.ttf

$ context --fontsdir=/tmp/a-random-folder/ <filename>.tex
[...]
system          > ConTeXt  ver: 2025.07.08 17:48 LMTX  fmt: 2025.7.10  int: english/english
[...]
mkxl run stats  > loaded fonts: 4 files: bitcountgriddouble-regular.ttf, latinmodernmathcompanion-regular.otf, latinmodern-math.otf, lmroman10-regular.otf
[...]
system          | total runtime: 0.330 seconds of 0.429 seconds

$ context --arguments=fontsdir=/tmp/a-random-folder/ <filename>.tex  # Alternative to the above, gives the exact same output

which gave the following result:

output

2
  • Thank you! That works. Is there a way to reference fontsdir from the --arguments list instead of as a separate argument? Such as: mtxrun --environment=main --arguments=themesdir=/path/to/themes/,imagesdir=/path/to/themes/images,fontsdir=/path/to/themes/fonts. I've tried about a dozen ways to access \env{fontsdir} (or arguments.environment and variations thereof) within the Lua code block to no avail. Commented Jul 17 at 16:50
  • 1
    @DaveJarvis You just need to put table.merge(document.arguments, utilities.parsers.settings_to_hash(document.getargument("arguments", ""))) somewhere before document.getargument("fontsdir"); see the edit. Commented Jul 18 at 5:34

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.