Zenn
📝

Typst 0.13.0 の内容を早めに深堀り

2025/02/20に公開
5

はじめに

本記事では、2025/02/19 にリリースされた Typst 0.13.0 の新機能や変更点を紹介します。

ピックアップ

影響が大きいと考えられるものや、個人的に気になった新機能などを取り上げます。 特に、破壊的変更には 💥 のサインを付けています。

💥 「正式な段落 (proper paragraph)」という概念の追加

v0.12 までは本文のテキストはもちろん、図のキャプションやページ番号に至るまでありとあらゆるテキストを段落とみなしていました。 しかし、中には意味的には段落とみなすべきでないものも含まれています。 視覚で情報を得るのが困難な方のための読み上げ機能(スクリーンリーダー)などは意味的に正しく段落と呼べるもののみ読み上げるべきです。

そこで Typst v0.13 では、「正式な段落 (proper paragraph) [1]」という概念が新たに導入され、単なるインラインのテキストと正式な段落を明示的に区別するようになりました。

正式な段落と単なるインラインテキストには以下の違いがあります。

  • par() 関数への setshow ルール変更は正式な段落にのみ反映され、インラインテキストには反映されない。

  • スクリーンリーダーなどの支援技術がどのように読み上げるかどうかが変わる。

  • 現時点では HTML export にのみ影響。

  • 正式な段落は HTML export 時に <p> タグで囲まれる。

また、正式な段落として扱われるものは以下の2種類あります。

  • ドキュメントのルートに存在するテキストは正当な段落として扱われる。

  • block などのコンテナ内に存在するテキストは、そのコンテナがブロックレベルのコンテンツを保持している場合にのみ正当な段落として扱われる。

    • 例: #heading[見出しのテキスト][見出しのテキスト] は、ブロックレベルのコンテンツを保持していないため正当な段落ではない。

    • 例: 以下の #quote の引数のコンテンツは、改段落というブロックレベルのコンテンツを保持しているため、正当な段落として扱われる。

      #quote(block: true)[
         A logical subdivison of textual content.
      
         Typst automatically collects inline-level elements into paragraphs. Inline-level elements include text, horizontal spacing, boxes, and inline equations.
      ]
      
      • 空行は #parbreak() と等価で、#parbreak() はブロックレベルのコンテンツであることに注意。
  • 2番目のルールを応用することで、コンテナ内で「正式な段落」として扱いたいかどうかを制御できます。たとえば以下のテキストをコンパイルすると以下のような結果となります。

    #set text(font: "Noto Serif CJK JP")
    #show par: set text(fill: blue)
    #show quote: block.with(stroke: (left: 2pt + gray), outset: (y: 6pt))
    
    = 見出しは正当な段落ではない
    
    正当な段落は青字で表示されるようにした。
    本文は普通にブロックになる。
    
    #quote(block: true)[
      ここは正当な段落ではない。
    ]
    
    #quote(block: true)[
      改段落を挟むと、正当な段落になる。
    
      改段落を挟むと、正当な段落になる。
    ]
    
    == 強制的に正当な段落にする
    
    #quote(block: true)[
      `#parbreak()` を末尾につければ正当な段落になる。#parbreak()
    ]
    
    == ブロック内を強制的にインラインにする例
    
    #quote(block: true)[
      #block[段落をそれぞれ block で囲めば、その中身は正当な段落として扱われなくなる。]
    
      #block[block で囲むことでスペーシングが変化する点は注意。]
    ]
    


    正当な段落とみなされる場所とそうでない場所

💥 outline 機能の改善

Typst で見出しや図表などの目次を作成するのに用いられる outline() 関数周辺の API が大きく変わり、カスタマイズの幅が広がりました。 またデフォルトの outline() 関数の見た目にも以下のような変化があります。

  • 見出しの階層構造に合わせてインデントされるようになった

  • 長い見出しを折り返すとき、折り返し行の開始位置がナンバリングの後となり、より自然になった

  • 見出しとページ数の間の点の間隔が広がった


デフォルトの見出しの組まれ方の比較(左: v0.12.0, 右: v0.13.0)

outline の体裁を変更する方法も新しくなりました。outline をカスタマイズして使っていた方はドキュメントを参照しつつ、実装を見直しましょう。

生バイト列をファイルとして渡せるようになった

Typst にはファイルパスを受け付ける関数やパラメータがあります。たとえば以下のようなものが挙げられます。

関数 機能
image("/path/to/file") 画像ファイルを読み込む
json("/path/to/file") JSON ファイルを読み込む
plugin("/path/to/file") WebAssembly ファイルを読み込んでプラグインとして使う
bibliography("/path/to/file") YAML や BibLaTeX 形式のファイルを読み込んで参考文献のリストとして使う
raw(theme: "/path/to/file") コードブロックの配色を定義するテーマを読み込む

一方、外部のファイルをそのまま読み込むだけでなく、Typst 側でこれらのデータを作成したり読み込んだデータを動的に加工したりするユースケースもあります。 v0.13 からは、文字列の代わりにバイト列を渡すことで Typst から直接データを渡せるようになりました。

またそれに伴い、今まで同様の用途で用意されていた json.decode() などの関数が deprecated となりました。

数式内で "a" などの文字列が立体で表示されるようになった

Typst の数式内では、アルファベットを $"avg"$ のようにダブルクォートで囲むことでその文字を立体で出すことができます。 ところが、$"a"$ のようにアルファベット1文字の場合、v0.12 まではなぜかイタリックで表示される(通常の $a$ と変わらない)挙動でした。 以前から不思議な仕様だと思っていましたが、こちらはバグだったようです。 v0.13 で修正され、 $"a"$ も立体で出るようになりました。

フォントのカバー範囲を明示的に指定できるようになった

フォントを指定する際に、どの種類の文字にそのフォントを適用するか指定できるようになりました。和文と欧文とで異なるフォントを用いたいときなどに便利です。 今のところ predefined coverage set は "latin-in-cjk" のみですが、正規表現を与えることで複雑な文字種のセットに対してフォントを指定することも可能です。

#set text(font: (
  (name: "Noto Sans CJK JP", covers: regex("[\p{scx:Han}]")),  // 漢字はサンセリフ
  "Noto Serif CJK JP",  // それ以外はセリフ
))

HTML export が部分的にサポートされた

HTML で出力する機能がついに試験的にサポートされました。

ローカルで試す場合、いつもどおり Typst の文書を書いた後に以下のコマンドを実行すれば HTML ファイルが生成されます。

typst compile input.typ --features html --format html

まだあくまで部分的なサポートであり、すべての要素に対応しているわけではありませんが、 見出しや箇条書き、基本的な表組みなどであればすでにサポートされているようです。

また、新たに提供された以下の機能を使えば、現在 HTML export に対応していない要素も条件分岐でアドホックに解決できそうです。

  • target() 関数: PDF などを出力するモードなのか HTML を出力するモードなのかを出力する。

  • html.elem(): 任意の HTML 要素を挿入する(HTML モードでのみ有効)。

注意点

Typst v0.13 時点で確認しておくべき箇所、今後の変更で影響しうる注意点をまとめました。

  • context 関連で対応できる構文の削除

    • style() 関数や context 外での counter.display() など、 context 記法で代替される旧記法が削除されました。

      • 使用している場所がある人は、context 式への置き換えを行ってください。
  • 変数 x の型を判定する際の書き方として、現在は2種類の書き方があります。

    • type(x) == int のように型と直接比較する 方法。こちらは v0.8 から導入された書き方であり、現在はこちらが推奨されています。

    • type(x) == "integer" のように文字列と比較する 方法。こちらは古い書き方であり、v0.14.0 で削除予定です。

    文字列と比較する方法がコードに含まれている方は速やかに修正することをおすすめします。

  • 今後、予約語として is が追加される可能性があるとのことです。 is を変数や関数の識別子に用いるのは控えましょう。

その他の変更点一覧

新機能のみ紹介し、バグ修正は省略します。

レイアウト関連

  • par()first-line-indet パラメータに辞書を指定できるようになり、適用範囲を選択できるようになった

    • 連続する段落の最初の行だけを 1.0em インデントする → (amount: 1.0em, all: false)

    • 全段落の最初の行を 1.0em インデントする → (amount: 1.0em, all: true)

  • ref()form パラメータに "page" を指定することでページ数を参照できるようになった

  • document()description パラメータが追加され、PDF や HTML のメタデータに反映できるようになった

  • enum()reversed パラメータが追加された

    • true のとき、 3. 2. 1. のように番号の振り方が大きい数字から小さくなっていきます。要素の順番そのものは変わりません。
  • 見出しなどのナンバリングで Greek numbering がサポートされた

  • link() 関数がブロック要素などのコンテナを囲む場合、ブロック全体に対して1つのリンクが作成されるようになった

    • v0.12 まではコンテナ内の子要素全てにそれぞれリンクが付いており、ブロック内に大量の子要素があるとき PDF サイズが大きくなっていました。
  • page カウンタを表示する際、page の numbering が考慮されるようになった

  • path() に代わり curve() 関数が使えるようになった

    • path() よりも記法が直感的になり、より多くのことができるようになりました。

    • path() は deprecated となり、将来的には path がファイルパス型を表すものに変更される予定とのこと。 すぐに互換性が崩れることはないと思いますが、現在 path 関数を使っている方は早めに curve 関数に切り替えることをおすすめします。

  • image() の引数に生のバイト列を渡せるようになった

    • Typst のコード中でバイト列を直接構成し、ラスタ画像を生成することができます。
  • image()scaling パラメータが追加され、PNG エクスポート時・PDF ビューワでの閲覧時にラスタ画像を表示する方法が指定できるようになった

    • scaling: "smooth": 平滑化アルゴリズムによりスケールされます。

    • scaling: "pixelated": 最近謗法などのアルゴリズムにより、ピクセル感を保ってスケールされます。

    • デフォルト (auto) ではビューワ依存となります(多くのケースでは smooth scaling となる模様)。

  • image()icc パラメータが追加され、画像の ICC プロファイルを指定できるようになった

  • gradient 型に center()radius() メソッドなどが追加された

    • いずれも color gradient の中心や半径といった情報を返すものです。
  • 💥 WASM プラグインの扱いが変わり、 plugin 型を提供する代わりに、 plugin() という関数が用意されるようになった

    • 返り値はモジュール (module) となったため、 import 構文で直接インポートできるようになりました。
  • WASM プラグインで transition API がサポートされた

    • プラグイン呼び出しの関数に(制限付きながら)副作用が持たせられるようになりました。純粋関数にはできない、WASM プラグインの内部状態を更新するような操作ができるようです。初回だけコストの高い計算をするときなどに便利とのこと。
  • 💥 インポート時に、リネーム無しで動的にインポートを行うことができなくなった

    • たとえば import "ot" + "her.typ" といった書き方がエラーになるとのこと[2]

    • 動的インポート自体ができなくなったわけではなさそうなので、該当する方はリネームするなどして回避しましょう。

文字組み関連

  • 💥 symbol において、1つの variants に同一の modifier を指定するとエラーを返すようになった

    • Typst では #sym.arrow.r (→) といった記法で様々な Unicode 文字が入力できます。

      • $arrow.r$ など、数式内で使われるものもそれです。
    • arrow.r.r の部分は modifier と呼ばれ、矢印記号の様々な亜種から所望のものを選ぶ用途で使用します。arrow.r.double.bar のように複数つけることができます。

    • 実はこのシンボルは symbol() コンストラクタを用いて自前定義でき、modifier の指定も可能です。

    • この modifier のうち、同一のものを複数定義すると v0.13 からはエラーが出るようになります。

  • smallcaps()all パラメータが追加され、大文字もスモールキャピタルにできるようになった

  • 以下の設定がコードブロックに影響を及ぼさなくなった

    • par()justification パラメータの設定(両端揃え)

    • text()cjk-latin-spacing パラメータの設定(CJK 文字と Latin 文字間の空白)

数式関連

  • 数式内での関数呼び出し構文の幅が広がった

    • hyphen つきのキーワード引数が使えるようになりました。

    • argument spreading 構文にも対応しました。

  • アクセントの見た目が改善された

  • lcm オペレータが追加された

プログラミング・構文関連

  • arguments 型が +{} 構文で join できるようになった

    • 公式での紹介はあっさりしていますが、個人的には地味にありがたい機能追加です。
  • 💥 対応する開括弧を持たない閉じ括弧がトップレベルに存在する場合エラーが出力されるようになった

  • 💥 set 構文にて、識別子と括弧の間に空白を入れることができなくなった

  • 💥 0b10000pt のように、prefix と単位を両方つけることができなくなった

    • v0.12 までは構文上許されていたものの、意味的には常に 0 として評価されていたとのこと。

エクスポート関連

  • PDF/A-3b 仕様のエクスポートに対応

  • PDF のタイムスタンプがタイムゾーンの情報を持つようになった

関連資料

脚注
  1. proper を「正式な」と訳すのが適切なのか分かりませんが、本記事では一旦「正式な段落」という訳をあてることにします。 ↩︎

  2. 筆者はそもそもこのような書き方が v0.12 までできたことを知りませんでした… ↩︎

5

Discussion

ログインするとコメントできます