Typst 0.12.0 の内容を早めに深堀り
はじめに
本記事では、2024/10/19 にリリースされた Typst 0.12.0 の新機能や変更点を紹介します。
ピックアップ
多段組の文書にて、浮動図を段抜きで置けるようになった
公式でも目玉として取り上げられている機能追加です。v0.11 以前では多段組の本文中に #figure()
を指定しても、1列の中で浮動図を置くことしかできませんでしたが、 v0.12 では figure()
の scope
プロパティに "parent"
を指定することで、段をぶち抜きつつ浮動図を置けるようになりました。
浮動図を段抜きで置く例。公式ブログ記事より。
余談ですが、本機能の実現のために裏側のレイアウトエンジンを再実装したそうです。浮動図を横に置き、図に合わせてテキストを流し込む機能も将来的には見据えているとのこと。追加されるのが楽しみですね。
Typst CLI における PDF 出力での絵文字が正式にサポートされた
今まで Typst CLI にて #emoji.snowman
などの記法を用いて絵文字を出力すると、下図左のように線だけの表示となってしまっていました。そのため v0.11 時点では svg-emojis
パッケージを用いるなどの回避が必要でしたが、v0.12 で下図右のように適切に表示できるようになりました。カジュアルなスライドを作成するときなどに重宝しそうですね。
なお、筆者環境では #emoji.snowman
ではなく ⛄
(U+26C4) をそのまま記述しても正常に表示されました。
絵文字のレンダリング結果。左: v0.11.0, 右: v0.12.0。
段落に行番号を振れるようになった
par.line
関数の numbering
プロパティを指定することで、段落の余白に行番号をふることができるようになりました。主に学術論文などでのユースケースを想定しているようです。
段落に行番号をふる例。公式ブログ記事より。
- デフォルトは文の開始側(left-to-right な文書なら左側)に番号がつきます。
number-margin
プロパティで挙動を変更できます。 -
numbering-scope
プロパティを指定すると、「文書全体を通してインクリメントされる」か「ページごとにリセットされる」かの挙動を変更できます。
par()
関数のプロパティから直接指定できるようになった
【破壊的変更】段落間空白が 今まで段落間の空白を指定するときは
#show par: set block(spacing: 2em)
などとする必要がありましたが、v0.12 では、新たに par()
に追加された spacing
プロパティを用いて
#set par(spacing: 2em)
と設定する方式となりました。
本変更は破壊的変更として扱われているため注意が必要です。前者で段落間空白を設定していた人は、後者で設定し直すようにしましょう。
block()
のプロパティの影響を受けるようになった
【破壊的変更】ブロックレベルの要素が list()
, grid()
, stack()
などで作られるブロックが、軒並み block()
関数に指定されているプロパティの影響を受けるようになりました。従来とは異なる挙動のため、既存の文書のレイアウトが崩れる可能性があります。
#set page(height: auto)
#set block(stroke: 1pt + red, spacing: 100pt)
#lorem(20)
#lorem(20)
- Poem
- Roses are red.
- Violets are blue.
set block
で block のプロパティを変更したときの挙動の変化。左: v0.11.0, 右: v0.12.0。
ブロック直後の改行を抑制できるプロパティが追加された
block.sticky
プロパティを使うことで、ブロック直後の改ページを抑制できるようになりました。見出し直後の改ページを避けたいケースなどで有用です。
import 構文のバリエーション追加
-
入れ子になっているモジュール構造において、孫の要素を直接インポートできるようになりました。
// v0.11 以前では以下のように書く必要があった #import "@local/my-classfile:0.1.0": component; #import component: colors // v0.12 からはこう書ける #import "@local/my-classfile:0.1.0": component.colors
-
インポートする要素をカッコで囲むことができるようになり、その結果、複数行にまたがってインポート文を書けるようになりました。インポートしたい関数やモジュールが多いとき便利そうです。
#import "@local/my-classfile:0.1.0": ( component, layout, )
std
モジュールの追加
Typst には様々な組み込み関数が定義されており、中には text()
や align()
といった使用頻度の高い英単語もあります。そのため、Typst でプログラミングを行うときに意図せず組み込み関数を別の変数で上書き(シャドーイング)してしまうことがありました。
// `align` 引数を省略したら中央揃え、明示的に指定したらその align で揃えるような関数を定義したい。
// しかし、以下は組み込み関数の `align()` を引数の `align` で上書きしてしまっているため、意図した挙動にならない。
#let myalign(align: center, body) = align(align, body)
// よって、名前を変えるなどして回避する必要があった
#let myalign(align_: center, body) = align(align_, body)
// キーワード引数名が "align" とならないのはちょっとイケてない…
#myalign(align_: right)[Example Text.]
v0.12 では std
というモジュールが標準で使えるようになり、この問題が解決されました。
// `align` は上書きされるが `std.align` はそのまま使える
#let myalign(align: center, body) = std.align(align, body)
// スムーズに "align" という名前のキーワード引数が使える!
#myalign(align: right)[Example Text.]
パフォーマンス・ファイルサイズの改善
新機能ではありませんが、このあたりも地味に嬉しい改善点です。
-
レイアウトエンジン(テキストや図などを紙面に配置する処理)がマルチスレッドで動作するようになりました。
pagebreak()
関数などによる明示的な改ページが行われている箇所からの配置を並列で行うことができます。大規模な文書でのパフォーマンス改善が期待できます。 -
段落の両端を揃える paragraph justification という処理が高速化されました。短い段落が多い場合に効果が高く、最大6倍ほど高速になるとのことです。
-
フォントのサブセット化の方法を改善することで、PDF 出力のファイルサイズが少なくなりました。地味に嬉しい変更ですね。
その他の変更
変更点が非常に多いため、ここでは機能追加に関するものを中心に一部を取り上げます。バグ修正などは割愛しますので、全ての変更点が知りたい方は公式の Changelog を参照してください。
レイアウト関連
-
-
#place.flush()
を呼び出すことで、それまでの浮動図を全て表示してから以降の contents を表示させることができます。
-
-
skew()
関数の追加-
scale()
やrotate()
と合わせれば任意の Affine 変換が行えます。
-
-
page.header
/page.footer
プロパティにauto
が指定できるようになった-
auto
を指定すると、page.numbering
やpage.number-align
プロパティに応じたページ番号が自動で付与されます。 - 挙動としてはプロパティ省略時の挙動と同じですが、v0.11 以前は一度明示的に指定した後にデフォルトの挙動に戻せませんでした。
auto
の追加により、デフォルトに戻すことが可能となりました。
-
-
repeat.gap
及びrepeat.justify
プロパティの追加- ピリオドなどを繰り返す際、文字間の余白を明示的に指定できるようになりました。
また、横幅に合わせた伸長を行うかどうかも指定できるようになりました。
- ピリオドなどを繰り返す際、文字間の余白を明示的に指定できるようになりました。
-
block
,image
,rect
,square
,ellipse
,circle
のheight
プロパティにfr
単位の長さが指定できるようになった- fraction (
fr
) は親要素の長さを分割するときの比率を示す単位で、グリッドの幅を均等にする際などに用います。1fr
をheight
に指定したブロックを2つ並べれば、2ブロックが同じ高さになるように隙間を埋めてくれます。
具体例
#set page(width: 200pt, height: 200pt, margin: 10pt) #block(width: 100%, height: 1fr, fill: red.lighten(80%), radius: 5pt)[ #align(center + horizon)[#lorem(5)] ] #block(width: 100%, height: 1fr, fill: blue.lighten(80%), radius: 5pt)[ #align(center + horizon)[#lorem(5)] ]
- fraction (
-
scale()
関数のx
,y
プロパティに(相対値ではない)長さを直接指定できるようになった- 「横幅を3倍に拡大する」といった指定に加え、「横幅が
300pt
になるよう拡大する」という指定ができるようになりました。
- 「横幅を3倍に拡大する」といった指定に加え、「横幅が
-
block.above
とblock.below
の値が context 式中で取れるようになった
文字組み関連
-
デフォルトフォントが "Libertinus Serif" になった
- もともとのデフォルトであった "Linux Libertine" の後継フォントです。
- この変更により、組版結果が若干変わる可能性があります。
-
利用できないフォントファミリーを指定した場合に警告を発するようになった
- 今までは利用できないものを指定しても、単に無視していました。
-
スマートクォート機能のアルゴリズムを改善した
-
text.costs
プロパティを追加し、行分割アルゴリズムに置けるコスト関数の重みをカスタマイズできるようにした- 以下のコストごとの重みを比率で指定できます。
-
hyphenation
(1単語をハイフネーションで分割するコスト) -
runt
(段落の末尾が1単語で終わるコスト) -
widow
(段落の最終行だけが次のページに置かれるコスト) -
orphan
(段落の最初の行だけが前のページに置かれるコスト)
-
コードブロックのハイライト言語に「Typst の数式モード」が指定できるようになった
- 言語に
typm
を指定すれば、Typst の数式部分だけを書いてハイライトさせることができます。
- 言語に
-
以下の言語の基本的な国際化 (basic i18n)
- ガリシア語
- カタロニア語
- ラテン語
- アイスランド語
- ヘブライ語
-
一部の言語の "hyphenation duplication" を実装
- 具体的には以下の言語です。
- チェコ語
- クロアチア語
- 低地ソルブ語
- ポーランド語
- ポルトガル語
- スロバキア語
- スペイン語
- これらの言語では、ハイフネーションを行うときに行末だけでなく行頭にもハイフンを置く必要があるそうです。 https://github.com/typst/typst/issues/3235
- 具体的には以下の言語です。
-
smallcaps()
がshow
やset
で指定できる関数 (element function) になった-
smallcaps()
を使うときだけフォントを変える、といったことが可能になります。
-
-
raw.theme
プロパティにnone
を指定することで、シンタックスハイライトをオフにできるようになった -
text.stylistic-set
プロパティに複数の数字が指定できるようになった
数式
-
ブロックレベルの数式が複数ページにまたがるようになった
- この挙動は
show math.equation: set block(breakable: false)
でオフにできます。
- この挙動は
-
行列やベクトルの大きさがより一貫するようになった
-
詳しくは把握しきれていませんが、添字などによる高さの違いの影響を受けづらくなったようです。
行列を組んだときの様子。カッコの大きさの違いに注目。左: v0.11.0, 右: v0.12.0。
-
-
stretch
関数 が追加され、等号や矢印などのグリフを伸ばせるようになった-
$ H stretch(=)^"define" U + p V $
とすることで、"define" の幅だけ伸びた等号を作ることができます。 - 引き伸ばせるグリフは一部のみで、数式フォント依存です。
-
-
mat.delim
,vec.delim
,cases.delim
プロパティが、デリミタまたはフェンスとみなせるいかなる Unicode 文字も受け付けるようになった- フェンスとはたとえば
"|"
(U+007c) のような文字です。 - ただし、
delim: "||"
といった指定はできなくなりました。delim: bar.double
などで代替する必要があります。
- フェンスとはたとえば
-
vec.align
,mat.align
プロパティが追加され、行列やベクトルの要素の揃え方を指定できるようになった- 整数で構成されたベクトルなどは右揃えで書くと見栄えが良さそうです。
-
underparen
,overparen
,undershell
,overshell
関数の追加-
underbrace
系の仲間です。 - "shell bracket" とはいわゆる亀甲括弧
〔〕
です。
-
-
~
が二項関係子として解釈されるようになった- 今まで
tilde.op
と書いていたところのショートハンドとして~
が使えるようになります。 - 逆に単なるチルダとして書いていた部分も
tilde.op
として解釈されてしまうので注意。
- 今まで
その他、記法・組版周りの変化
-
#set document()
ルールの制限が緩和され、文書の冒頭以外にも書けるようになった -
list()
,enum()
,term()
におけるspacing
プロパティが、tight list のときにも反映されるようになった -
tight list において、リスト前の余白の付け方が変わり、段落が先行しているときのみ余白がタイトになる仕様になった
-
quote()
要素が locatable(typst query
などで検索できる要素)になった -
複数行にまたがる見出しの外観調整のため、
heading()
関数にhanging-indent
プロパティ が追加された- デフォルトの見出しも改善され、複数行にまたがるときは "1." などのナンバリングの幅だけ自動でインデントが付くようになりました。
-
path()
およびpolygon()
関数にfill-rule
プロパティが追加された- 星型のように辺が交差する多角形を塗るときの挙動を、
"non-zero"
または"even-odd"
の2値で調整できます。
- 星型のように辺が交差する多角形を塗るときの挙動を、
-
decimal
型の追加- 今まで少数を表す型は浮動小数点数の
float
型のみですが、固定小数点数のdecimal
型が新たに追加されました。小数の計算を厳密に行うことができます。
- 今まで少数を表す型は浮動小数点数の
-
array
型へのメソッド追加-
to-dict()
:((k1, v1), (k2, v2), ...)
の形の配列を(k1: v1, k2: v2, ...)
にするやつ。 -
reduce()
:fold
メソッドと似ているが、初期値を最初の配列の要素とするやつ。 -
windows()
:(1, 2, 3, 4, 5,)
から((1, 2, 3), (2, 3, 4), (3, 4, 5))
を作るやつ。
-
-
array.zip()
メソッドにexact
引数を追加-
exact
引数にtrue
を指定すると、組み合わせる2配列の要素の個数が一致しないときエラーになります。false
を指定したときは従来通り、長い方のあまりが無視されます。
-
エクスポート
-
PDF/A の部分的なサポート
- エクスポート時に
PDF/A
を有効にすることで、より長期保存に適した形での PDF を出力できるようになりました。- CLI では
--pdf-standard a-2b
オプションを指定することで有効化できます。
- CLI では
- 現時点では PDF/A-2b のみサポートしています。
- エクスポート時に
-
page.fill
プロパティをnone
にすると、PDF や SVG でエクスポートする際にも背景が透過するようになった- 従来の挙動(PDF での背景を透明に、PNG や SVG での背景を白にする)を指定したいときは
auto
を設定します。
- 従来の挙動(PDF での背景を透明に、PNG や SVG での背景を白にする)を指定したいときは
CLI・ツール
-
--pages
オプションの追加- エクスポートする際に特定のページ番号を指定できるようになりました。
-
--package-path
,--package-cache-path
オプションの追加 -
--ignore-system-fonts
フラグの追加- システムフォントの読み込みを無効化します。システム依存の要素を減らし、より再現性の高い文書を作成するのに有効です。
-
複数の画像ファイルにエクスポートするとき、
t
(total pages),p
(current page),0p
(0パディングされた page)が出力ファイル名に指定できるようになった
おわりに
約5ヶ月ぶりのバージョンアップということもあり、変更点が非常に多かった印象です。0.12.0-rc1
が出た当初から本記事の準備をしていたのですが、目を引く機能追加・不具合修正が非常に多く、作業をまとめるのも大変でした。今回は大規模な再実装があったためリリースが遅くなったとのことなので、次回のバージョンはもう少し早めに来るかもしれません。
本記事で誤りを見つけた方は、コメントにてご指摘ください。
Discussion