Typst における関数とルール
そろそろ Typst の関数とルール設定について,そろそろちゃんと調べようと思って。 本当は「Typst に関する雑多な話」で軽く触れるだけにするつもりだったが,思ったより量があったので記事を立てることにした。
関数の定義と呼び出し
まずは一番簡単な関数を考えてみる。
#let fnc(it) = {
it
};
これは引数をそのまま返すだけの関数である。
この関数の引数に "Hello"
を渡して呼び出すと
#fnc("Hello")
引数の内容がそのまま出力される。

引数には(出力可能なものであれば)なんでも渡せる。 数値を入れることもできるし,何なら関数を入れ子にしてもよい。
#fnc(fnc("Hello"))
もうひとつ。
Typst の関数呼び出しではコンテントブロック(角括弧 [ ... ]
で囲まれる領域)を関数呼び出しの後ろに付けることができる。
これをコンテント引数(content argument)と呼ぶ。
#fnc[Hello]
コンテント引数(content argument)は呼び出された側では content
型の引数としてセットされる。
つまり #fnc("Hello")
と #fnc[Hello]
は(str
と content
の型の違い以外は)ほぼ同じ機能である。
ついでの話として,呼び出す側はコンテント引数を複数並べることができる。
#fnc2[Hello][world]
この場合,呼び出される側は以下のように定義する。
#let fnc2(..it) = {
it
}
#fnc2[Hello][world]
このときの出力結果は以下の通り。

it
に arguments
型で受けているのが分かる。
arguments
型は pos
メソッドで array
型に変換できる。
名前付き引数
次は文字列を色付きで出力することを考えてみる。 関数定義は以下の通り。
#let colorText(color: red, it) = {
text(fill: color)[#it]
}
color: red
は名前付き引数(named parameter)と呼ばれる。
名前付き引数には既定値がつく(上述のコードでは red
が既定値)。
この関数の呼び出しは以下のように書く。
#colorText[Hello] #colorText(color: blue)[world]
名前付き引数は省略可能で省略した場合は既定値になる。 もちろん
#colorText("Hello") #colorText(color: blue, "world")
などと書くこともできる。 出力結果は同じで以下の通り:

Show ルール
show
キーワードを使って指定した対象に対し show ルールを設定できる。
#let colorText(color: red, it) = {
text(fill: color)[#it]
}
#show heading: it => colorText(color: blue, it)
= Heading 1
== Heading 1.1
上のコードの it
は show
キーワードで指定した対象を無名関数のコンテント引数として渡したもの。
全ての関数で共通に用意されている with
メソッドを使うことで以下のようにコンテント引数を省略できる。
#let colorText(color: red, it) = {
text(fill: color)[#it]
}
#show heading: colorText.with(color: blue)
= Heading 1
== Heading 1.1
出力結果はいずれも同じでこんな感じ。

Show ルールの対象は(出力可能なものなら)なんでもよくて,たとえば
#let colorText(color: red, it) = {
text(fill: color)[#it]
}
#show "Hello": colorText
Hello World
みたいな記述もできる。 なお,コンテント引数以外に引数がない(または省略できる)場合は,上のように関数名だけを指定できる。
このコードの出力結果は以下の通り:

Show ルールの対象には selector
も指定できる。
たとえば where
メソッドを使って以下のように記述できる。
#let colorText(color: red, it) = {
text(fill: color)[#it]
}
#show heading.where(level: 1).or(heading.where(level: 2)): colorText
= Heading 1
== Heading 1.1
=== Heading 1.1.1
出力結果は以下の通り:

Show ルールの対象がない場合,文書全体が対象となる。
#let colorText(color: red, it) = {
text(fill: color)[#it]
}
#show: colorText.with(color: blue)
#lorem(40)
ちなみに lorem
は指定した単語数のランダムな文章(欧文1)を生成する関数である。
出力結果は以下の通り:

Show ルールは逐次処理されるのか
Show ルールがどのように効いてくるか試してみた。
まずはこれ。
#let colorText(color: red, it) = {
text(fill: color)[#it]
}
= Heading 1
== Heading 1.1
#show heading: colorText
= Heading 2
== Heading 2.1
出力結果は以下の通り:

まぁ,これは予想通り。
次はこれ。
#let colorText(color: red, it) = {
text(fill: color)[#it]
}
= Heading 1
== Heading 1.1
#show heading: colorText
= Heading 2
== Heading 2.1
#show heading: it => colorText(color: blue, it)
= Heading 3
== Heading 3.1
希望としては 黒 → 赤 → 青 の順で変わってほしいのだが…

んー。
ひょっとして show ルールって遡って適用されるのだろうか。
外部パッケージを import
したときに show ルールが衝突したら面倒なことになりそう。
Show ルールの設計はちょっと気をつけないといけないかもしれない。
Set ルール
text
や image
あるいは heading
や par
などドキュメント要素に紐づく組込み関数は「要素関数(element function)」と言うそうな。
要素関数は set
キーワードを使い set ルールで名前付き引数の既定値を変更することができる。
Some functions are associated with elements like headings or tables. When called, these create an element of their respective kind. In contrast to normal functions, they can further be used in set rules, show rules, and selectors.
ドキュメントのルートで set ルールを指定すると,逐次処理で指定位置以降に適用される。
#set text(font: "Noto Serif CJK JP", lang: "ja")
明朝体
#set text(font: "Noto Sans CJK JP", lang: "ja")
ゴシック体
出力結果は以下の通り:

Show ルールの中で set ルールを指定した場合,その show ルールの中でのみ set ルールが適用される。
#set text(font: "Noto Serif CJK JP", lang: "ja")
#show heading: it => {
set text(font: "Noto Sans CJK JP")
it
}
= ゴシック体
明朝体
set
キーワードのみの記述ならコンテント引数を省略して
#set text(font: "Noto Serif CJK JP", lang: "ja")
#show heading: set text(font: "Noto Sans CJK JP")
= ゴシック体
明朝体
などと記述することもできる。
出力結果はいずれも同じでこんな感じ。

なお let
キーワードで定義したユーザ関数は要素関数ではないので set ルールは使えない。
文書ファイルを分割した際のルール設定
文書ファイルを分割して import
や include
で読み込む場合,子ドキュメントで設定した set および show ルールは親ドキュメントには適用されないので注意(親ドキュメントから子ドキュメントへはルールが継承される)。
子ドキュメントで記述した set および show ルールを親ドキュメントに適用させるには(テンプレートで使う手法)ルールを記述した関数を import
で読み込み,親ドキュメントの show ルールを使って関数を呼び出す。
#let initFonts(font-name: "New Computer Modern", body) = {
set text(
lang: "ja",
font: font-name,
size: 10pt,
)
body
}
#import "child.typ": initFonts
#show: it => initFonts(
font-name: "Noto Sans CJK JP",
it
)
こんにちわ、世界!
または with
メソッドを使って
#import "child.typ": initFonts
#show: initFonts.with(
font-name: "Noto Sans CJK JP",
)
こんにちわ、世界!
などとコンテント引数を省略できる。
ブックマーク
ブックマークは「Typst に関するブックマーク」にてまとめています。
参考文献
- Typst完全入門: LaTeXより簡単、Markdownより強力、美しいドキュメント作成術
- doitsu (著)
- 2024-12-08 (Release 2024-12-08)
- Kindle版
- B0DPXBNTRS (ASIN)
- 評価
マークアップ言語および組版ツールである Typst についての解説。 Kindle 版のみの提供。固定レイアウトではないためレイアウトが崩れまくって読みにくい。この手の技術解説書は固定レイアウトの Kindle 版か,いっそ PDF で出してほしい。でも Typst についてまとまった解説のある日本語の本は他に見当たらなかったのでありがたい。
-
日本語の文を生成する
roremu
パッケージを公開されている方もいる。感謝! ↩︎