Physics Lab. 2024のロゴ

アドカレ|13日目

Typstの空白について

はじめに

Typstは、最近流行りの組版ソフトウェアです。この記事ではTypstで若干複雑な空白の扱いについて解説します。

この記事において、「空白」という単語はRustのchar::is_whitespacetrueになる文字、つまりUnicode Character DatabaseにおけるWhite_Spaceカテゴリに属する文字を指します。例えば半角スペース、全角スペース、改行は空白です。

この記事の内容はTypst 0.10.0のソースコードを基にしています。バージョンが異なると仕様が違う可能性があります。

Typstのコンパイル

まずコンパイルの全体像を見てみましょう。Typstのコンパイルには4つの段階があります(ソースコード)。

  1. Parsing: 入力ファイルからトークン列を作成し、構文木にパースする。構文木に型をつける。
  2. Evaluation: マークアップを評価し、変数とコンテンツの組であるモジュールにする。
  3. Layouting: モジュールのレイアウトを行い、ドキュメントを作る。ドキュメントは要素の位置が指定されたフレームから成る。
  4. Exporting: フレームをpdfにする。

空白の取り扱いに大きく関係するのはParsingです。以下ではパーサの動作について解説します。

パーサのモード

Typstのパーサには3つのモードがあります。

  1. Markup: 文章とマークアップ
  2. Code: プログラムのコード
  3. Math: 数式

ファイルの先頭はMarkupモードから始まります。Markupモードで#が現れると、直後の1つの式(ブロックでもよい)がCodeモードで読み取られます。またMarkupモードで$が現れると、次の$までがMathモードで読み取られます。

また、Codeモードで[]で囲まれたコンテンツブロックを使うと、その中はMarkupモードになります{}で囲まれたブロックでは、その中はCodeモードのままです。

Markupモードにおける空白

Markupモードでは、空白の列に改行がいくつ含まれるか[1]が重要です。

  • 改行を1つ以下だけ含む空白の列は、1つの半角スペースと等価です。
  • 改行を2つ以上含む空白の列は、改段落parbreakになります。

この仕様により、行の先頭の空白は無視されます。

Codeモードにおける空白

識別子の区切り

Codeモードでは、空白は識別子の区切りとしての意味しかありません。ただしCodeモードでの識別子における-の扱いとの兼ね合いで問題が起こることがあります。

Typstの識別子は基本的にはUAX31で規定されているものです。つまりアルファベットや漢字、ひらがな、カタカナから成るような文字列は識別子になります。ただしCodeモードでは_で始まる文字列や_,-が2文字目以降にある文字列も識別子として許可されています。このため-の前後に空白があるかによって識別子のパースが変わります。

#let x = 6
#let x-1 = 42

#str(x-1)     // 42
#str(x - 1)   // 5
#str(x -1)    // 5
//#str(x- 1)  // これは`x-`という識別子がないのでエラー

image.png

引き算の意味で-を使うときは、両端にスペースを入れたほうがよいでしょう。

#の後の空白

また、MarkupモードやMathモードから#でCodeモードに入った際、元のモードに戻るために空白を用いると、スペースが挿入されます。;を使えばスペースを挿入せずに元のモードに戻ることができます。

#let te = "te"

#te xt

#te;xt

image.png

Mathモードにおける空白

識別子の区切り

MathモードでもCodeモードと同じく基本的に数式中の空白には識別子の区切りとしての意味しかありません。ただしMathモードでは識別子に_,-を含めることが認められておらず、-は常に引き算または負の符号の意味で用いられます。よって識別子についての問題はありません。 数式中で_,-を含む識別子を使いたいときは#を使ってCodeモードに移る必要があります。

数式がブロックになるか

ブロック数式とインライン数式の区別は空白で行われます。数式に入る$の後に空白があり、数式から出る$の前に空白がある数式はブロック数式になります。それ以外の数式はインラインになります。

$x^2+1$    // インライン

$ x^2+1$   // インライン

$x^2+1
$          // インライン

$ x^2+1 $  // ブロック

$ x^2+1
$          // ブロック

$
x^2+1
$          // ブロック

数式の前後に何があるかは関係ありません。

|の前後の空白

|の前後の空白は特別に意味を持ちます。

$
x | y \
x|y
$

image.png

おわりに

空白の扱いは若干面倒ですが、見た目に直結します。規則を理解して正しく使えるようにしましょう。


  1. \r,\n,\r\nはどれも1個の改行として数えます。 ↩︎