├── .gitignore ├── HISTORY.md ├── LICENSE.md ├── README-ja.md ├── README.md ├── Satyristes ├── doc ├── enumitem.pdf └── enumitem.saty ├── satysfi-enumitem-doc.opam ├── satysfi-enumitem.opam └── src ├── counter.satyh ├── enumitem.satyh ├── itemfmt.satyh └── param.satyh /.gitignore: -------------------------------------------------------------------------------- 1 | *.satysfi-aux 2 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # HISTORY 2 | 3 | ## 3.0.1 (2021-11-23) 4 | 5 | * fix document file 6 | 7 | ## 3.0.0 (2021-11-14) 8 | 9 | * major changes in interface and implementation 10 | * change to allow page breaks in the content in listings 11 | * add more low-level notation for listings 12 | * multiple paragraphs can be placed within a single item 13 | * the style of a label can be changed in the middle of the listing. 14 | 15 | ## 2.0.0 (2020-06-13) 16 | 17 | * change interfaces 18 | * add xgenlisting command 19 | * add global parameters 20 | * register satysfi-enumitem-doc package for Satyrographos 21 | 22 | ## 1.1.0 (2020-02-24) 23 | 24 | * add description commands 25 | 26 | ## 1.0.1 (2020-02-02) 27 | 28 | * add build file and package file for Satyrographos 29 | 30 | ## 1.0.0 31 | 32 | * add `satysfi-enumitem` package 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Mogami Shinichi 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README-ja.md: -------------------------------------------------------------------------------- 1 | # satysfi-enumitem 2 | 3 | `enumitem` パッケージは, 4 | 箇条書き(番号付きリスト,番号なしリスト,定義リスト)を 5 | [SATySFi](https://github.com/gfngfn/SATySFi) で実現するパッケージです. 6 | LaTeX の [enumitem パッケージ](https://www.ctan.org/pkg/enumitem) から名付けました. 7 | 8 | このパッケージは以下の機能を提供しています. 9 | 10 | - 標準パッケージ (`itemize`) に比べ自由度およびカスタマイズ性の高い箇条書きコマンド 11 | - ネスト可能な番号付き箇条書き環境 12 | - 定義リスト 13 | 14 | ## インストール 15 | 16 | SATySFi のパッケージマネージャである 17 | [Satyrographos](https://github.com/na4zagin3/satyrographos) 18 | を用いてインストールできます. 19 | Satyrographos そのものをインストールした後(詳細は 20 | [README of Satyrographos](https://github.com/na4zagin3/satyrographos/blob/master/README.md) 21 | をご覧ください), 22 | ターミナルで以下のように叩けばインストールされます: 23 | 24 | ``` 25 | opam install satysfi-enumitem 26 | satyrographos install 27 | ``` 28 | 29 | インストールが完了した後は, 30 | プリアンブル部分(`.saty` ファイルの冒頭)で以下の文を記述することで 31 | パッケージで提供するコマンドを使えるようになります. 32 | 33 | ``` 34 | @require: enumitem/enumitem 35 | ``` 36 | 37 | ## 使い方 38 | 39 | [ドキュメント](doc/enumitem.pdf) をご覧ください. 40 | 41 | 42 | ## ライセンス 43 | 44 | MIT 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # satysfi-enumitem 2 | 3 | `enumitem` is a [SATySFi](https://github.com/gfngfn/SATySFi) package 4 | for flexible ordered/unordered/description lists. 5 | This package was named after the 6 | [enumitem](https://www.ctan.org/pkg/enumitem) package in LaTeX. 7 | 8 | This package provides the following features/commands: 9 | 10 | - More flexible and customizable listing commands than those in the standard `itemize` package 11 | - Ordered lists that can be nested 12 | - Commands for description list (definition list) 13 | 14 | ## Installation 15 | 16 | You can install `enumitem` package with 17 | [Satyrographos](https://github.com/na4zagin3/satyrographos), 18 | a package manager of SATySFi. 19 | First you should install Satyrographos 20 | (see [README of Satyrographos](https://github.com/na4zagin3/satyrographos/blob/master/README.md)) 21 | and then type in your terminal as follows: 22 | 23 | ``` 24 | opam install satysfi-enumitem 25 | satyrographos install 26 | ``` 27 | 28 | After installation, you can import this package by writing the following sentence in preamble (top of `.saty` file): 29 | 30 | ``` 31 | @require: enumitem/enumitem 32 | ``` 33 | 34 | ## Usage 35 | 36 | See [the documentation of enumitem](doc/enumitem.pdf) (Japanese only). 37 | 38 | ## License 39 | 40 | MIT 41 | -------------------------------------------------------------------------------- /Satyristes: -------------------------------------------------------------------------------- 1 | ;; For Satyrographos 0.0.2 series 2 | (version 0.0.2) 3 | 4 | (library 5 | (name "enumitem") 6 | (version "3.0.1") 7 | (sources 8 | ((packageDir "src") 9 | )) 10 | (opam "satysfi-enumitem.opam") 11 | (dependencies 12 | ( 13 | (base ()) 14 | ))) 15 | 16 | (libraryDoc 17 | (name "enumitem-doc") 18 | (version "3.0.1") 19 | (workingDirectory "doc") 20 | (build 21 | ((satysfi "enumitem.saty" "-o" "enumitem.pdf"))) 22 | (sources 23 | ((doc "enumitem.pdf" "doc/enumitem.pdf"))) 24 | (opam "satysfi-enumitem-doc.opam") 25 | (dependencies ((enumitem ())))) 26 | -------------------------------------------------------------------------------- /doc/enumitem.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monaqa/satysfi-enumitem/f2444a530aa2082d912d9ffdc45341639c9d3b54/doc/enumitem.pdf -------------------------------------------------------------------------------- /doc/enumitem.saty: -------------------------------------------------------------------------------- 1 | @require: stdjabook 2 | @require: code 3 | @require: math 4 | @require: color 5 | @require: hdecoset 6 | @require: vdecoset 7 | @require: base/length 8 | @import: ../src/enumitem 9 | 10 | open EnumitemAlias 11 | 12 | % custom commands 13 | 14 | let-block ctx +ctx ctxflst bt = read-block (ctxflst |> List.fold-left (fun ctx ctxf -> ctxf ctx) ctx) bt 15 | 16 | let document record bt = StdJaBook.document record '<% 17 | +ctx[fun ctx -> ( 18 | let fsize = get-font-size ctx in 19 | ctx |> set-paragraph-margin fsize fsize 20 | % |> set-font-size 5pt 21 | |> set-leading (fsize *' 1.6) 22 | |> set-code-text-command (command \code) 23 | % ctx 24 | )](bt); 25 | >% 26 | 27 | let-inline ctx \cjk it = 28 | let ctx = ctx |> set-dominant-narrow-script Kana in 29 | read-inline ctx it 30 | 31 | let font-ratio-latin = 1. 32 | let font-ratio-cjk = 0.88 33 | let font-latin-italic = (`Junicode-it`, font-ratio-latin, 0.) 34 | let font-latin-bold = (`Junicode-b` , font-ratio-latin, 0.) 35 | let font-cjk-gothic = (`ipaexg` , font-ratio-cjk , 0.) 36 | let-inline ctx \emph inner = 37 | let ctx-bf = 38 | ctx |> set-font Latin font-latin-italic 39 | |> set-font HanIdeographic font-cjk-gothic 40 | |> set-font Kana font-cjk-gothic 41 | in 42 | read-inline ctx-bf inner 43 | 44 | let-block +code code = 45 | '<+ctx[set-font-size 10pt; set-paragraph-margin 6pt 6pt; set-leading 16pt;]<+Code.code(code);>> 46 | 47 | let-block ctx +block-frame bt = 48 | let decoset = VDecoSet.simple-frame 0.5pt Color.black Color.white in 49 | block-frame-breakable ctx (7pt, 7pt, 10pt, 10pt) decoset (fun ctx -> read-block ctx bt) 50 | 51 | let-block +example str bt = 52 | '<% 53 | +code(str); 54 | +block-frame(bt); 55 | >% 56 | 57 | let-block +dd dt it-dd = '< +ditem?:(fun it -> {\emph{#it;}}){#dt;}{#it-dd;}<> > 58 | 59 | let-block +param name type- desc = 60 | % '< +ditem?:(fun it -> {\emph{#it;}}){#name;}{(#type-;)}< #desc; > > 61 | '< +item?:(description ?:(fun it -> {\emph{#it;}}) name){(#type-;)}<#desc;> > 62 | 63 | let ooalign ib1 ib2 = 64 | let (wid, ht, dp) = get-natural-metrics ib1 in 65 | inline-graphics wid ht dp (fun pt -> [draw-text pt ib1; draw-text pt ib2]) 66 | let ib-box ctx = 67 | let ctx = ctx |> set-dominant-narrow-script Kana in 68 | read-inline ctx (string-unexplode [0x25A1] |> embed-string) 69 | let ib-checkmark ctx = 70 | let ctx = ctx |> set-dominant-narrow-script Kana in 71 | read-inline ctx (string-unexplode [0x2713] |> embed-string) 72 | 73 | let-inline ctx \mark-todo = ib-box ctx 74 | let-inline ctx \mark-done = ooalign (ib-box ctx) (ib-checkmark ctx) 75 | 76 | let-block +todo-list bt = '< +itemize(text-label {\mark-todo;\ })(bt); > 77 | let-block +todo it = '< +item?:(text-label {\mark-todo;\ })(it)<> > 78 | let-block ctx +done it = 79 | let ctx = ctx |> set-text-color (Color.gray 0.5) in 80 | read-block ctx '< +item?:(text-label {\mark-done;\ })(it)<> > 81 | 82 | let-block +genin it = '< +item?:(text-label{下人「}){#it;」}<> > 83 | let-block +rouba it = '< +item?:(text-label{老婆「}){#it;」}<> > 84 | 85 | let-inline ctx \textbf it = 86 | let ctx = 87 | ctx |> set-font Latin font-latin-bold 88 | |> set-font Kana font-cjk-gothic 89 | |> set-font HanIdeographic font-cjk-gothic 90 | in 91 | read-inline ctx it 92 | 93 | let question = 94 | let labelf idx = 95 | let num = idx |> arabic |> embed-string in 96 | {\textbf{設問#num;}.\ } 97 | in 98 | index-label labelf 99 | |> EnumitemFormat.set-label-inherit 100 | |> EnumitemFormat.set-indent (fun ctx wid-label -> get-font-size ctx *' 1.0) 101 | 102 | let-inline \jugem = { 103 | 寿限無,寿限無,五劫のすりきれ, 104 | 海砂利水魚の水行末・雲来末・風来末, 105 | 食う寝るところに住むところ, 106 | やぶら小路のぶら小路, 107 | パイポパイポ,パイポのシューリンガン, 108 | シューリンガンのグーリンダイ, 109 | グーリンダイのポンポコピーのポンポコナーの長久命の長助. 110 | } 111 | 112 | let-inline \qf = { The quick brown fox jumps over the lazy dog. } 113 | 114 | in 115 | 116 | document (| 117 | title = {Enumitem パッケージ}; 118 | author = {\@monaqa}; 119 | date = {2020/06/13}; 120 | show-title = true; 121 | show-toc = true; 122 | |) '<% 123 | 124 | +section{パッケージの概要}< 125 | 126 | +p{ 127 | `enumitem` は \SATySFi; にて豊富な箇条書きや番号付きのリストを提供するパッケージです。 128 | 標準にもすでに `itemize` という名前のパッケージが用意されているものの、 129 | 本パッケージではより自由度の高い箇条書きを提供します。 130 | 具体的には、以下のような箇条書きを書くことができます: 131 | } 132 | +listing{ 133 | * デフォルトで豊富なスタイルのラベルを選択できる 134 | * 番号付き箇条書き環境をネストさせることができる 135 | * ネストごとに箇条書きのスタイルを変更できる 136 | * 箇条書きのラベルの体裁を項目ごとに変更できる 137 | * 定義リストを作成できる 138 | * ユーザ自身がスタイルを拡張できる 139 | } 140 | +p{ 141 | 本ドキュメントは \SATySFi; v0.0.6 及び `enumitem` パッケージ v3.0.1 の組み合わせでの仕様を述べたものです。 142 | 旧バージョン、すなわちメジャーバージョンが 0, 1, 2 のいずれかであるものとの互換性は無く、 143 | たとえコマンド名が同じであっても引数のルールが異なることなどがあります。 144 | バージョンの違いに注意してください。 145 | } 146 | 147 | +subsection{用語集}< 148 | 149 | +p{ 150 | ここでは以下のような用語を用います。 151 | } 152 | 153 | +description< 154 | +dd{箇条書き}{ 155 | いくつかの単語や文章、段落などを分けて書き並べたリストのこと。 156 | 本パッケージではそのうち、本文と独立した段落で組まれるものを扱う。 157 | } 158 | +dd{項目}{ 159 | 箇条書きを構成する1つ1つの要素。1つのラベルと本文で構成され、 160 | ネストされた箇条書きの場合は1つ以上の子項目を有する場合がある。 161 | } 162 | +dd{番号付き箇条書き}{ 163 | 番号や順序のわかる記号を用いてラベルがふられた箇条書き。 164 | } 165 | +dd{番号無し箇条書き}{ 166 | 順序のない記号などを用いてラベルがふられた箇条書き。 167 | } 168 | +dd{ラベル}{ 169 | 箇条書きの開始を表すために先頭につける記号や文字の列。 170 | 通常、番号付き箇条書きであれば “1.” や “(a)”、 171 | 番号無し箇条書きであれば “\eval(EnumitemFormatUtil.shape-bullet);” といったテキストや記号などが用いられる。 172 | } 173 | > 174 | 175 | > 176 | 177 | > 178 | 179 | +section{`enumitem` をはじめよう}< 180 | 181 | +subsection{`enumitem` パッケージのインストール}< 182 | +p{ 183 | `enumitem` パッケージは Satyrographos によってインストールすることができます。 184 | } 185 | 186 | +code(``` 187 | opam install satysfi-enumitem 188 | satyrographos install 189 | ```); 190 | 191 | +p{ 192 | `opam list satysfi-enumitem` などのコマンドで 193 | バージョン3系がインストールされていることを確認したら、次に進みましょう。 194 | } 195 | > 196 | 197 | +subsection{パッケージの読み込み}< 198 | +p{ 199 | \SATySFi; の文書ファイルやヘッダファイルで外部のパッケージを用いるには以下のようにします。 200 | } 201 | 202 | +code(``` 203 | @require: enumitem/enumitem 204 | ```); 205 | 206 | +p{ 207 | さらに、 `EnumitemAlias` というモジュールも open しておきましょう。 208 | これは enumitem パッケージで定義されているモジュールの一つであり、 209 | 箇条書きの体裁を変更するための関数、定義リスト専用のコマンドなど便利な機能がまとまっています。 210 | まとめると、文書ファイルの場合は以下のような文言をファイルに書けばよいということになります。 211 | 「本文」のところは、各クラスファイルの書き方に従ってください。 212 | } 213 | 214 | +code(``` 215 | @require: enumitem/enumitem 216 | 217 | % プリアンブル(トップレベル宣言) 218 | open EnumitemAlias 219 | 220 | in % プリアンブルの終わり 221 | 222 | document (| ... |) '< % ここの書き方はクラスファイルに応じて変わる 223 | % 本文 224 | ... 225 | > 226 | ```); 227 | 228 | +p{ 229 | 準備ができたら、本文のどこかに以下のように書いてみましょう。 230 | } 231 | +code(``` 232 | +listing{ 233 | * foo 234 | * bar 235 | ** barfoo 236 | ** barbar 237 | * baz 238 | } 239 | ```); 240 | 241 | +p{ 242 | もし正常にパッケージが読み込まれていれば、以下のように出力されるはずです。 243 | } 244 | 245 | +block-frame< 246 | +listing{ 247 | * foo 248 | * bar 249 | ** barfoo 250 | ** barbar 251 | * baz 252 | } 253 | > 254 | 255 | > 256 | 257 | +subsection{基本的なコマンドの使用}< 258 | +p{ 259 | `enumitem` は `+listing` 及び `+enumerate` コマンドを提供します。 260 | 標準の `itemize` パッケージを使ったことがある人にとっては馴染み深いでしょう。 261 | 使い方は標準のコマンドと(オプション引数を除き)ほぼ変わりません。 262 | } 263 | 264 | +example(``` 265 | +listing{ 266 | * hoge 267 | * fuga 268 | ** fuga1 269 | *** fuga11 270 | *** fuga12 271 | ** fuga2 272 | } 273 | ```)<% 274 | +listing{ 275 | * hoge 276 | * fuga 277 | ** fuga1 278 | *** fuga11 279 | *** fuga12 280 | ** fuga2 281 | } 282 | >% 283 | 284 | +p{ 285 | 番号付きの箇条書きのネストにも対応しています。 286 | } 287 | 288 | +example(``` 289 | +enumerate{ 290 | * hoge 291 | * fuga 292 | ** fuga1 293 | *** fuga11 294 | *** fuga12 295 | ** fuga2 296 | } 297 | ```)<% 298 | +enumerate{ 299 | * hoge 300 | * fuga 301 | ** fuga1 302 | *** fuga11 303 | *** fuga12 304 | ** fuga2 305 | } 306 | >% 307 | 308 | > 309 | > 310 | 311 | +section{Gallery}< 312 | 313 | +subsection{ラベルの変更}< 314 | +p{ 315 | `+listing` コマンドを用いて番号無し箇条書きが書けることは既に見たとおりですが、 316 | オプション引数を指定することでラベルを自由に変更することができます。 317 | 以下の例はラベルに `bullet` 及び `white-bullet` を指定した箇条書きであり、 318 | ラベルがそれぞれ黒丸、白丸に置き換わっていることがわかります。 319 | } 320 | 321 | +example(``` 322 | +listing?:(bullet){ 323 | * 水馬、赤いな。ア、イ、ウ、エ、オ。 324 | ** 浮藻に小蝦もおよいでる。 325 | } 326 | +listing?:(white-bullet){ 327 | * 水馬、赤いな。ア、イ、ウ、エ、オ。 328 | ** 浮藻に小蝦もおよいでる。 329 | } 330 | ```)< 331 | +listing?:(bullet){ 332 | * 水馬、赤いな。ア、イ、ウ、エ、オ。 333 | ** 浮藻に小蝦もおよいでる。 334 | } 335 | +listing?:(white-bullet){ 336 | * 水馬、赤いな。ア、イ、ウ、エ、オ。 337 | ** 浮藻に小蝦もおよいでる。 338 | } 339 | > 340 | 341 | +p{ 342 | `+enumerate` コマンドも同様にオプション引数を用いてラベルを変更できます。 343 | } 344 | 345 | +example(``` 346 | +enumerate?:(paren-alph){ 347 | * 水馬、赤いな。ア、イ、ウ、エ、オ。 348 | ** 浮藻に小蝦もおよいでる。 349 | * 柿の木、栗の木。カ、キ、ク、ケ、コ。 350 | ** 啄木鳥こつこつ、枯れけやき。 351 | * 大角豆に醋をかけ、サ、シ、ス、セ、ソ。 352 | ** その魚淺瀬で刺しました。 353 | } 354 | ```)< 355 | +enumerate?:(paren-alph){ 356 | * 水馬、赤いな。ア、イ、ウ、エ、オ。 357 | ** 浮藻に小蝦もおよいでる。 358 | * 柿の木、栗の木。カ、キ、ク、ケ、コ。 359 | ** 啄木鳥こつこつ、枯れけやき。 360 | * 大角豆に醋をかけ、サ、シ、ス、セ、ソ。 361 | ** その魚淺瀬で刺しました。 362 | } 363 | > 364 | 365 | +p{ 366 | なお、`+listing` と `+enumerate` の違いはオプション引数のデフォルト値のみであるため、 367 | 上の例で `+listing?:(paren-alph){ ... }` と書いても同じ結果となります。 368 | % とはいえマークアップ上の視認性から、 369 | % 番号付き箇条書きには原則 `+enumerate` を使用するほうが望ましいでしょう。 370 | } 371 | 372 | +p{ 373 | もう少し自由度高くラベルを設定したい場合もあるでしょう。 374 | `text-label` 関数を用いると、任意のインラインテキストをラベルとして取り扱うことができます。 375 | } 376 | 377 | +example(``` 378 | +listing?:(text-label {一.}){ 379 | * 水馬、赤いな。ア、イ、ウ、エ、オ。 380 | ** 浮藻に小蝦もおよいでる。 381 | * 柿の木、栗の木。カ、キ、ク、ケ、コ。 382 | ** 啄木鳥こつこつ、枯れけやき。 383 | * 大角豆に醋をかけ、サ、シ、ス、セ、ソ。 384 | ** その魚淺瀬で刺しました。 385 | } 386 | ```)< 387 | +listing?:(text-label {一.}){ 388 | * 水馬、赤いな。ア、イ、ウ、エ、オ。 389 | ** 浮藻に小蝦もおよいでる。 390 | * 柿の木、栗の木。カ、キ、ク、ケ、コ。 391 | ** 啄木鳥こつこつ、枯れけやき。 392 | * 大角豆に醋をかけ、サ、シ、ス、セ、ソ。 393 | ** その魚淺瀬で刺しました。 394 | } 395 | > 396 | 397 | +p{ 398 | `index-label` 関数を用いると、 399 | インデックスの値(整数値)を引数に取ってインラインテキストを返すような関数を与えることで 400 | 対応するラベルを生成することができます。 401 | 自由度の高い番号付き箇条書きを生成するしたい場合に便利です。 402 | } 403 | 404 | +example(``` 405 | +enumerate?:( 406 | let square-idx idx = 407 | let it = (idx * idx) |> arabic |> embed-string in 408 | {\ #it;.\ } 409 | in 410 | index-label square-idx 411 | ){ 412 | * 水馬、赤いな。ア、イ、ウ、エ、オ。 413 | ** 浮藻に小蝦もおよいでる。 414 | * 柿の木、栗の木。カ、キ、ク、ケ、コ。 415 | ** 啄木鳥こつこつ、枯れけやき。 416 | * 大角豆に醋をかけ、サ、シ、ス、セ、ソ。 417 | ** その魚淺瀬で刺しました。 418 | } 419 | ```)< 420 | +enumerate?:( 421 | let square-idx idx = 422 | let it = (idx * idx) |> arabic |> embed-string in 423 | {\ #it;.\ } 424 | in 425 | index-label square-idx 426 | ){ 427 | * 水馬、赤いな。ア、イ、ウ、エ、オ。 428 | ** 浮藻に小蝦もおよいでる。 429 | * 柿の木、栗の木。カ、キ、ク、ケ、コ。 430 | ** 啄木鳥こつこつ、枯れけやき。 431 | * 大角豆に醋をかけ、サ、シ、ス、セ、ソ。 432 | ** その魚淺瀬で刺しました。 433 | } 434 | > 435 | 436 | +p{ 437 | ここまで見てきた例はいずれもルールが同じネストレベルのインデックスにのみ依存しており、 438 | ラベルが箇条書きのネストの深さに応じて変化する、といったことがありませんでした。 439 | しかし、親の項目には番号付きのラベルを、 440 | 子の項目には番号無しのラベルを振る、といったケースも珍しくありません。 441 | ネストの深さに応じてラベルを変化させたい場合は `with-depth` 関数を用います。 442 | `with-depth` 関数はラベルのリストを引数に取り、 443 | 項目のネストの深さが ${n} である項目はリストの ${n} 番目のラベルを用いて組まれます。 444 | } 445 | 446 | +example(``` 447 | +enumerate?:(with-depth [paren-alph; text-label {続き:}]){ 448 | * 水馬、赤いな。ア、イ、ウ、エ、オ。 449 | ** 浮藻に小蝦もおよいでる。 450 | * 柿の木、栗の木。カ、キ、ク、ケ、コ。 451 | ** 啄木鳥こつこつ、枯れけやき。 452 | * 大角豆に醋をかけ、サ、シ、ス、セ、ソ。 453 | ** その魚淺瀬で刺しました。 454 | } 455 | ```)< 456 | +enumerate?:(with-depth [paren-alph; text-label {続き:}]){ 457 | * 水馬、赤いな。ア、イ、ウ、エ、オ。 458 | ** 浮藻に小蝦もおよいでる。 459 | * 柿の木、栗の木。カ、キ、ク、ケ、コ。 460 | ** 啄木鳥こつこつ、枯れけやき。 461 | * 大角豆に醋をかけ、サ、シ、ス、セ、ソ。 462 | ** その魚淺瀬で刺しました。 463 | } 464 | > 465 | 466 | +example(``` 467 | +listing?:({|一.|二.|三.|} |> List.map text-label |> with-depth){ 468 | * 五十音 469 | ** 水馬、赤いな。ア、イ、ウ、エ、オ。 470 | *** 浮藻に小蝦もおよいでる。 471 | ** 柿の木、栗の木。カ、キ、ク、ケ、コ。 472 | *** 啄木鳥こつこつ、枯れけやき。 473 | ** 大角豆に醋をかけ、サ、シ、ス、セ、ソ。 474 | *** その魚淺瀬で刺しました。 475 | } 476 | ```)< 477 | +listing?:({|一.|二.|三.|} |> List.map text-label |> with-depth){ 478 | * 五十音 479 | ** 水馬、赤いな。ア、イ、ウ、エ、オ。 480 | *** 浮藻に小蝦もおよいでる。 481 | ** 柿の木、栗の木。カ、キ、ク、ケ、コ。 482 | *** 啄木鳥こつこつ、枯れけやき。 483 | ** 大角豆に醋をかけ、サ、シ、ス、セ、ソ。 484 | *** その魚淺瀬で刺しました。 485 | } 486 | > 487 | 488 | > 489 | 490 | +subsection{複雑な箇条書き}< 491 | 492 | +p{ 493 | ここまでに挙げた使い方だけでも多くの箇条書きを組むことができますが、 494 | より複雑な箇条書きを組みたい場合もあるかもしれません。たとえば 495 | \listing{ 496 | * 1つの箇条書きの途中でラベルのルールを変えたい 497 | * 項目の中に複数の段落や別行立て数式などを入れたい 498 | } 499 | といった場合、今までのコマンドでは対応することができません。 500 | これらは、 `+itemize` 及び `+item` というコマンドを用いて組むことができます。 501 | } 502 | 503 | +example(``` 504 | +itemize(dot-arabic)< 505 | +item{`+item` では、1番目の必須引数に書いたものが項目となる。}< 506 | +item{ネストさせることも可能。}<> 507 | +item{2番目の必須引数に書いたものが子項目となる。}<> 508 | > 509 | +item{ 510 | デフォルトでは `+itemize` の必須引数で指定したラベルが用いられる。 511 | したがって、ここはアラビア数字で番号付けされている。 512 | }<> 513 | +item?:(paren-roman){ここはローマ数字での番号付け。}< 514 | +item{`+item` の1つ目の必須引数の前でラベルを指定すれば、自身のラベルが変わる。}<> 515 | +item{子の項目はローマ数字にならず、アラビア数字のまま。}<> 516 | > 517 | +item?:(paren-alph)({ここはアルファベットでの番号付け。})?:(bracket-arabic)< 518 | +item{ 519 | `+item` の2つ目の必須引数の前でラベルを指定すれば、 520 | 子の項目のラベルが全て変わる。 521 | }<> 522 | +item{今回の場合、ネストの中身は角括弧で囲まれたアラビア数字となる。}< 523 | +item{孫項目のラベルも角括弧で囲まれたアラビア数字。}<> 524 | > 525 | > 526 | +item{ここはアラビア数字。}<> 527 | > 528 | ```)< 529 | +itemize(dot-arabic)< 530 | +item{`+item` では、1番目の必須引数に書いたものが項目となる。}< 531 | +item{ネストさせることも可能。}<> 532 | +item{2番目の必須引数に書いたものが子項目となる。}<> 533 | > 534 | +item{ 535 | デフォルトでは `+itemize` の必須引数で指定したラベルが用いられる。 536 | したがって、ここはアラビア数字で番号付けされている。 537 | }<> 538 | +item?:(paren-roman){ここはローマ数字での番号付け。}< 539 | +item{`+item` の1つ目の必須引数の前でラベルを指定すれば、自身のラベルが変わる。}<> 540 | +item{子の項目はローマ数字にならず、アラビア数字のまま。}<> 541 | > 542 | +item?:(paren-alph)({ここはアルファベットでの番号付け。})?:(bracket-arabic)< 543 | +item{ 544 | `+item` の2つ目の必須引数の前でラベルを指定すれば、 545 | 子の項目のラベルが全て変わる。 546 | }<> 547 | +item{今回の場合、ネストの中身は角括弧で囲まれたアラビア数字となる。}< 548 | +item{孫項目のラベルも角括弧で囲まれたアラビア数字。}<> 549 | > 550 | > 551 | +item{ここはアラビア数字。}<> 552 | > 553 | > 554 | 555 | +p{ 556 | 項目の中に複数の段落を入れたいときにも `+itemize` と `+item` の組み合わせは有用です。 557 | } 558 | 559 | +example(``` 560 | +item{ 561 | 一つの項目に複数の段落を入れる例。 562 | `+item` の1番目の必須引数に入力されたものが段落となる。 563 | }< 564 | +p{ 565 | しかし、2番目の必須引数に `+p` コマンドなど通常のコマンドを入れると、 566 | 段落をはじめとしたブロックを後続させることができる。 567 | } 568 | +p{ 569 | 段落は当然複数置くことができる。 570 | } 571 | > 572 | 573 | +item{ 574 | 別行立て数式を配置する例。 575 | }< 576 | +math(${y = a}); 577 | 578 | +p{ 579 | インラインテキスト内で別行立て数式を配置するコマンドも存在するが、 580 | マークアップの意味合いは若干異なり、こちらは改段落が行われる。 581 | } 582 | > 583 | > 584 | ```)< 585 | +itemize(bullet)< 586 | +item{ 587 | 一つの項目に複数の段落を入れる例。 588 | `+item` の1番目の必須引数に入力されたものが段落となる。 589 | }< 590 | +p{ 591 | しかし、2番目の必須引数に `+p` コマンドなど通常のコマンドを入れると、 592 | 段落をはじめとしたブロックを後続させることができる。 593 | } 594 | +p{ 595 | 段落は当然複数置くことができる。 596 | } 597 | > 598 | 599 | +item{ 600 | 別行立て数式を配置する例。 601 | }< 602 | +math(${y = a}); 603 | 604 | +p{ 605 | インラインテキスト内で別行立て数式を配置するコマンドも存在するが、 606 | マークアップの意味合いは若干異なり、こちらは改段落が行われる。 607 | } 608 | > 609 | > 610 | > 611 | 612 | +p{ 613 | `+itemize` 及び `+item` は `+listing` などのコマンドと比較してより冗長な記述を必要とするものの、 614 | `+listing` などのコマンドでは表現できない複雑な箇条書きもパワフルに表現できます。 615 | 詳細は第 \ref(`enumitem-philosophy`); 章も参照。 616 | } 617 | 618 | +p{ 619 | なお、場合によっては 620 | `+listing` と `\sublist` などのコマンドを組み合わせて 621 | 複雑な箇条書きを実現できるケースもあります。 622 | } 623 | 624 | +example(``` 625 | +listing{ 626 | * 番号付き箇条書きと番号なし箇条書きの混用。 627 | ** 以下、番号無し箇条書き。 628 | \sublist(bullet){ 629 | * ここは番号なし箇条書き。 630 | * ここは番号なし箇条書き。 631 | * ここは番号なし箇条書き。 632 | } 633 | ** 以下、番号付き箇条書き。 634 | \sublist(dot-arabic){ 635 | * ここは番号付き箇条書き。 636 | * ここは番号付き箇条書き。 637 | * ここは番号付き箇条書き。 638 | } 639 | } 640 | ```)< 641 | +listing{ 642 | * 番号付き箇条書きと番号なし箇条書きの混用。 643 | ** 以下、番号無し箇条書き。 644 | \sublist(bullet){ 645 | * ここは番号なし箇条書き。 646 | * ここは番号なし箇条書き。 647 | * ここは番号なし箇条書き。 648 | } 649 | ** 以下、番号付き箇条書き。 650 | \sublist(dot-arabic){ 651 | * ここは番号付き箇条書き。 652 | * ここは番号付き箇条書き。 653 | * ここは番号付き箇条書き。 654 | } 655 | } 656 | > 657 | 658 | > 659 | 660 | +subsection{応用:To Do リスト}< 661 | 662 | +p{ 663 | `enumitem` を用いて To Do リストを実現することもできます。 664 | こちらは少し前準備が必要となります。まずはプリアンブル(トップレベル)にて以下のコマンドを定義します。 665 | } 666 | 667 | +code(``` 668 | let ooalign ib1 ib2 = 669 | let (wid, ht, dp) = get-natural-metrics ib1 in 670 | inline-graphics wid ht dp (fun pt -> [draw-text pt ib1; draw-text pt ib2]) 671 | let ib-box ctx = 672 | let ctx = ctx |> set-dominant-narrow-script Kana in 673 | read-inline ctx (string-unexplode [0x2713] |> embed-string) 674 | let ib-checkmark ctx = 675 | let ctx = ctx |> set-dominant-narrow-script Kana in 676 | read-inline ctx (string-unexplode [0x2501] |> embed-string) 677 | 678 | let-inline ctx \mark-todo = ib-box ctx 679 | let-inline ctx \mark-done = ooalign (ib-box ctx) (ib-checkmark ctx) 680 | ```); 681 | 682 | +p{ 683 | `\mark-todo;` は未完了タスクを表すラベル「\mark-todo;」を、 684 | `\mark-done;` は完了タスクを表すラベル「\mark-done;」を表しています。 685 | 上のコード例では用意されているフォントのグリフを重ね打ちするなどして作成したものの、 686 | 画像ファイルを読み込む、 687 | \SATySFi; のグラフィックス機能を用いて描画する、といった手法でラベルを用意することも可能です。 688 | } 689 | 690 | +p{ 691 | これらのコマンドと `+itemize` や `+item` コマンドを駆使することで、 692 | 以下のように To Do リストを組むことができます。 693 | } 694 | 695 | +example(``` 696 | +itemize(text-label {\mark-todo;\ })< 697 | +item?:(text-label {\mark-todo;\ }){ミルクを買う。}<> 698 | +item?:(text-label {\mark-todo;\ }){The \SATySFi;book を読む。}<> 699 | +item?:(text-label {\mark-done;\ }){\SATySFi; を完全に理解する。}<> 700 | +item?:(text-label {\mark-todo;\ }){課題を解く。}<> 701 | > 702 | ```)< 703 | +itemize(text-label {\mark-todo;\ })< 704 | +item?:(text-label {\mark-todo;\ }){ミルクを買う。}<> 705 | +item?:(text-label {\mark-todo;\ }){The \SATySFi;book を読む。}<> 706 | +item?:(text-label {\mark-done;\ }){\SATySFi; を完全に理解する。}<> 707 | +item?:(text-label {\mark-todo;\ }){課題を解く。}<> 708 | > 709 | > 710 | 711 | +p{ 712 | とはいえこれはマークアップと呼ぶには少し複雑すぎますね。 713 | もう少し楽に書くため、以下のようなコマンドを追加で定義してみましょう。 714 | ついでに、完了した項目は灰色となるような工夫を入れてみます。 715 | } 716 | 717 | +code(``` 718 | let-block +todo-list bt = '< +itemize(text-label {\mark-todo;\ })(bt); > 719 | let-block +todo it = '< +item?:(text-label {\mark-todo;\ })(it)<> > 720 | let-block ctx +done it = 721 | let ctx = ctx |> set-text-color (Color.gray 0.5) in 722 | read-block ctx '< +item?:(text-label {\mark-done;\ })(it)<> > 723 | ```); 724 | 725 | +example(``` 726 | +todo-list< 727 | +todo{ミルクを買う。} 728 | +todo{The \SATySFi;book を読む。} 729 | +done{\SATySFi; を完全に理解する。} 730 | +todo{課題を解く。} 731 | > 732 | ```)< 733 | +todo-list< 734 | +todo{ミルクを買う。} 735 | +todo{The \SATySFi;book を読む。} 736 | +done{\SATySFi; を完全に理解する。} 737 | +todo{課題を解く。} 738 | > 739 | > 740 | 741 | > 742 | 743 | +subsection{応用:定義リスト}< 744 | +p{ 745 | 定義リストとはいくつかの用語を並べて説明したり、定義を述べたりする際に用いられる箇条書きです。 746 | ラベルには通常その項目が説明する用語名が入り、本文でその説明が書かれる構造となっています。 747 | 定義リストは箇条書きとしては少し複雑ですが、 748 | 幸い、今まで見たとおり `enumitem` パッケージにはそういった複雑な箇条書きを表現するだけの十分な機能が備わっています。 749 | } 750 | 751 | +p{ 752 | 最も単純な定義リストは以下のようなものです。 753 | } 754 | 755 | +example(``` 756 | +description< 757 | +ditem{用語1}{ここに用語1の説明が入る。}<> 758 | +ditem{用語2}{ 759 | ここに用語2の説明が入る。用語2の説明は少し長い。 760 | 用語2の説明は少し長い。用語2の説明は少し長い。用語2の説明は少し長い。 761 | }<> 762 | +ditem{ちょっと長めの用語3}{ 763 | ここに用語3の説明が入る。用語3の説明は少し長い。 764 | 用語3の説明は少し長い。用語3の説明は少し長い。用語3の説明は少し長い。 765 | }< 766 | +pn{ 767 | 複数行にまたがる説明を入れることもできる。 768 | } 769 | > 770 | > 771 | ```)< 772 | +description< 773 | +ditem{用語1}{ここに用語1の説明が入る。}<> 774 | +ditem{用語2}{ 775 | ここに用語2の説明が入る。用語2の説明は少し長い。 776 | 用語2の説明は少し長い。用語2の説明は少し長い。用語2の説明は少し長い。 777 | }<> 778 | +ditem{ちょっと長めの用語3}{ 779 | ここに用語3の説明が入る。用語3の説明は少し長い。 780 | 用語3の説明は少し長い。用語3の説明は少し長い。用語3の説明は少し長い。 781 | }< 782 | +pn{ 783 | 複数の段落にまたがる説明を入れることもできる。 784 | } 785 | > 786 | > 787 | > 788 | 789 | +p{ 790 | 新たに登場した `+ditem` コマンドは `+item` と似ているものの、 791 | 追加で1番目にインラインテキストの必須引数を取り、 792 | そこに書かれたテキストをラベルとして表示します。 793 | また、`+ditem` のオプション引数を用いると、ラベル部分の体裁を変更することができます。 794 | 以下はラベルを強調して視認性を高めた例です。 795 | } 796 | 797 | +example(``` 798 | +description< 799 | +ditem?:(fun it -> {\emph{#it;}}){用語1}{ここに用語1の説明が入る。}<> 800 | +ditem?:(fun it -> {\emph{#it;}}){ちょっと長めの用語3}{ 801 | ここに用語3の説明が入る。用語3の説明は少し長い。 802 | 用語3の説明は少し長い。用語3の説明は少し長い。用語3の説明は少し長い。 803 | }<> 804 | > 805 | ```)< 806 | +description< 807 | +ditem?:(fun it -> {\emph{#it;}}){用語1}{ここに用語1の説明が入る。}<> 808 | +ditem?:(fun it -> {\emph{#it;}}){ちょっと長めの用語3}{ 809 | ここに用語3の説明が入る。用語3の説明は少し長い。 810 | 用語3の説明は少し長い。用語3の説明は少し長い。用語3の説明は少し長い。 811 | }<> 812 | > 813 | > 814 | 815 | +p{ 816 | 実際に用いる場合は、以下のようにプリアンブルでコマンドを定義しておくのが楽です。 817 | もし複数段落にまたがる説明を書く予定がないときは、 818 | 以下のようなコマンドを定義しておけば十分でしょう。 819 | } 820 | 821 | +code(``` 822 | let-block +dd dt it-dd = '< +ditem?:(fun it -> {\emph{#it;}}){#dt;}{#it-dd;}<> > 823 | ```); 824 | 825 | +p{ 826 | 上のように定義された `+dd` コマンドを用いれば、 827 | `+ditem` をそのまま用いるよりも楽に定義リストを記述できます。 828 | } 829 | 830 | +example(``` 831 | +description< 832 | +dd{用語1}{ここに用語1の説明が入る。} 833 | +dd{用語2}{ 834 | ここに用語2の説明が入る。用語2の説明は少し長い。 835 | 用語2の説明は少し長い。用語2の説明は少し長い。用語2の説明は少し長い。 836 | } 837 | +dd{ちょっと長めの用語3}{ 838 | ここに用語3の説明が入る。用語3の説明は少し長い。 839 | 用語3の説明は少し長い。用語3の説明は少し長い。用語3の説明は少し長い。 840 | } 841 | > 842 | ```)< 843 | +description< 844 | +dd{用語1}{ここに用語1の説明が入る。} 845 | +dd{用語2}{ 846 | ここに用語2の説明が入る。用語2の説明は少し長い。 847 | 用語2の説明は少し長い。用語2の説明は少し長い。用語2の説明は少し長い。 848 | } 849 | +dd{ちょっと長めの用語3}{ 850 | ここに用語3の説明が入る。用語3の説明は少し長い。 851 | 用語3の説明は少し長い。用語3の説明は少し長い。用語3の説明は少し長い。 852 | } 853 | > 854 | > 855 | 856 | > 857 | 858 | +subsection{ユースケース:大問と小問からなるレポート}< 859 | 860 | +p{ 861 | ここで、少々現実的な箇条書きを組んでみましょう。 862 | 以下はとある大学生のレポート課題を切り取ったものです。 863 | } 864 | 865 | +example(``` 866 | +enumerate?:(with-depth [question; paren-arabic; bullet]){ 867 | * Lebesgue 測度の劣加法性より(中略)、${m\paren{A} = m\paren{B}} が示された。 868 | * ** ${B_N = \bigcup_{n=1}^\infty A_n} とおく。(中略) 869 | ** 上限の定義より(中略) 870 | * ** ${C_0 = 1} は明らかである。 ${C_n} は(中略) 871 | ** ${C_n} は ${C_{n-1}} から適当な部分集合を取り除いてできる集合であるから 872 | ${C_n \subset C_{n-1}} となり、${\{C_n\}} は減少列である。(中略) 873 | ** \subitem< 874 | +item{内測度 ${m_{J*}\paren{C}}}< 875 | +pn{ 876 | ${C_n} を構成する1つ1つの閉区間の長さは(中略) 877 | } 878 | +pn{ 879 | したがって${m_{J*}\paren{C} = 0}。 880 | } 881 | > 882 | +item{外測度 ${m_{J*}\paren{C}}}< 883 | +pn{ 884 | ${C_n} を構成する1つ1つの閉区間の長さは(中略) 885 | } 886 | +pn{ 887 | したがって${m_{J*}\paren{C} = 1}。 888 | } 889 | > 890 | +pn{以上より、${C} は Jordan 非可測集合である。} 891 | > 892 | } 893 | ```)< 894 | +enumerate?:(with-depth [question; paren-arabic; bullet]){ 895 | * Lebesgue 測度の劣加法性より(中略)、${m\paren{A} = m\paren{B}} が示された。 896 | * ** ${B_N = \bigcup_{n=1}^\infty A_n} とおく。(中略) 897 | ** 上限の定義より(中略) 898 | * ** ${C_0 = 1} は明らかである。 ${C_n} は(中略) 899 | ** ${C_n} は ${C_{n-1}} から適当な部分集合を取り除いてできる集合であるから 900 | ${C_n \subset C_{n-1}} となり、${\{C_n\}} は減少列である。(中略) 901 | ** \subitem< 902 | +item{内測度 ${m_{J*}\paren{C}}}< 903 | +pn{ 904 | ${C_n} を構成する1つ1つの閉区間の長さは(中略) 905 | } 906 | +pn{ 907 | したがって${m_{J*}\paren{C} = 0}。 908 | } 909 | > 910 | +item{外測度 ${m_{J*}\paren{C}}}< 911 | +pn{ 912 | ${C_n} を構成する1つ1つの閉区間の長さは(中略) 913 | } 914 | +pn{ 915 | したがって${m_{J*}\paren{C} = 1}。 916 | } 917 | > 918 | +pn{以上より、${C} は Jordan 非可測集合である。} 919 | > 920 | } 921 | > 922 | 923 | +p{ 924 | ここで、 `question` は以下のようにユーザ定義された関数です。 925 | } 926 | 927 | +code(``` 928 | let question = 929 | let labelf idx = 930 | let num = idx |> arabic |> embed-string in 931 | {\textbf{設問#num;}.\ } 932 | in 933 | index-label labelf 934 | |> EnumitemFormat.set-label-inherit 935 | |> EnumitemFormat.set-indent (fun ctx wid-label -> get-font-size ctx *' 1.0) 936 | ```); 937 | 938 | > 939 | 940 | 941 | > 942 | 943 | +section?:(`enumitem-philosophy`){`enumitem` の設計思想}< 944 | +p{ 945 | `enumitem` v3.0.0 は以下の思想を元に設計されています。 946 | } 947 | +listing{ 948 | * \SATySFi; の文法に備わっている箇条書き用の平易な構文を可能な限り活用する。 949 | * 箇条書き用の構文でカバーできない機能については、専用のコマンドで対応する。 950 | * 関数を用いてラベルの体裁を指定することで、ユーザによる拡張ができるようにする。 951 | } 952 | +p{ 953 | 簡潔に書ける箇条書きと自由度の高い箇条書きを両立させるため、 954 | `enumitem` パッケージでは箇条書きの木構造を表現する2種類の表現方法が用意されています。 955 | } 956 | 957 | +subsection{糖衣構文ベースの記法}< 958 | +p{ 959 | 1つは \SATySFi; の箇条書きを表す専用の構文をそのまま用いてネストを表現する方法。 960 | こちらは標準の itemize パッケージでも採用されているインターフェースであり、簡単に記述できるのが利点です。 961 | ただし、設定できる項目の自由度はあまり高くありません。 962 | 便宜上、ここではこちらを\emph{糖衣構文ベースの記法}と呼びます。 963 | } 964 | 965 | +code(``` 966 | +listing?:(listing-default-label){ 967 | * aaa 968 | * bbb 969 | ** bbb の子1 970 | ** bbb の子2 971 | *** bbb の子2 の子1 972 | * ccc 973 | ** ccc の子1 974 | ** ccc の子2 975 | } 976 | ```); 977 | 978 | +p{ 979 | なお、 `+listing` のオプション引数のデフォルトは `listing-default-label` であるため、 980 | 上のコードの `?:(listing-default-label)` に相当する箇所は省略することができます 981 | (次の例との比較のためあえてつけています)。 982 | } 983 | > 984 | 985 | +subsection{ブロックベースの記法}< 986 | 987 | +p{ 988 | もう1つは \SATySFi; の箇条書き専用構文を用いることなく、 989 | `+itemize` 及び `+item` のみを用いてブロックテキストベースで箇条書きのネストを表現する方法。 990 | 星印 `*` だけでアイテムの始まりを示すことができた糖衣構文ベースの記法とは異なり、 991 | 項目のたびに `+item` を書く必要があります。 992 | 記法としては冗長になるものの、箇条書きを記述する際の自由度が高いというメリットがあります。 993 | こちらを\emph{ブロックベースの記法}と呼びます。 994 | } 995 | 996 | +code(``` 997 | +itemize(listing-default-label)< 998 | +item{aaa}<> 999 | +item{bbb}< 1000 | +item{bbb の子1}<> 1001 | +item{bbb の子2}< 1002 | +item{bbb の子2 の子1}<> 1003 | > 1004 | > 1005 | +item{ccc}< 1006 | +item{ccc の子1}<> 1007 | +item{ccc の子2}<> 1008 | > 1009 | > 1010 | ```); 1011 | 1012 | +p{ 1013 | ここで示した2つのコードは、どちらも最終的には同様の結果となることに注意してください。 1014 | } 1015 | 1016 | > 1017 | 1018 | +subsection{ブロックベースの記法の利点}< 1019 | 1020 | +p{ 1021 | 糖衣構文ベースでもブロックベースでも記述できる先程示したような箇条書きは、 1022 | より簡潔に書ける糖衣構文ベースの記法のほうが書きやすいといえます。 1023 | ブロックベースの記法の利点は、糖衣構文ベースの記法と比べて自由度が高く、 1024 | より複雑なルールに則った箇条書きを柔軟に表現できる点です。 1025 | } 1026 | 1027 | +p{ 1028 | ブロックベースの記法によって自然に実現できるものは、大きく分けて3種類あります。 1029 | 1つ目は、箇条書きの途中で項目の体裁を変更すること。 1030 | `+item` コマンドの1番目のオプション引数によって、自身の要素の体裁のみを変更できます。 1031 | } 1032 | 1033 | +example(``` 1034 | +itemize(dot-arabic-rec)< 1035 | +item{aaa}<> 1036 | +item?:(paren-alph){bbb}< 1037 | +item{bbb の子1}<> 1038 | +item{bbb の子2}< 1039 | +item{bbb の子2 の子1}<> 1040 | > 1041 | > 1042 | +item?:(white-bullet){ccc}< 1043 | +item{ccc の子1}<> 1044 | +item{ccc の子2}<> 1045 | > 1046 | > 1047 | ```)< 1048 | +itemize(dot-arabic-rec)< 1049 | +item{aaa}<> 1050 | +item?:(paren-alph){bbb}< 1051 | +item{bbb の子1}<> 1052 | +item{bbb の子2}< 1053 | +item{bbb の子2 の子1}<> 1054 | > 1055 | > 1056 | +item?:(white-bullet){ccc}< 1057 | +item{ccc の子1}<> 1058 | +item{ccc の子2}<> 1059 | > 1060 | > 1061 | > 1062 | 1063 | +p{ 1064 | そして、2番目のオプション引数によって自身の子要素の体裁全てを変更できます。 1065 | } 1066 | 1067 | +example(``` 1068 | +itemize(dot-arabic-rec)< 1069 | +item{aaa}<> 1070 | +item({bbb})?:(paren-alph)< 1071 | +item{bbb の子1}<> 1072 | +item{bbb の子2}< 1073 | +item{bbb の子2 の子1}<> 1074 | > 1075 | > 1076 | +item({ccc})?:(white-bullet)< 1077 | +item{ccc の子1}<> 1078 | +item{ccc の子2}<> 1079 | > 1080 | > 1081 | ```)< 1082 | +itemize(dot-arabic-rec)< 1083 | +item{aaa}<> 1084 | +item({bbb})?:(paren-alph)< 1085 | +item{bbb の子1}<> 1086 | +item{bbb の子2}< 1087 | +item{bbb の子2 の子1}<> 1088 | > 1089 | > 1090 | +item({ccc})?:(white-bullet)< 1091 | +item{ccc の子1}<> 1092 | +item{ccc の子2}<> 1093 | > 1094 | > 1095 | > 1096 | 1097 | +p{ 1098 | 2つ目は、項目の下に任意のブロックテキストを配置できること。 1099 | } 1100 | 1101 | +example(``` 1102 | +itemize(listing-default-label)< 1103 | +item{ここは最初の段落です。ラベルは最初の段落の冒頭に付きます。}< 1104 | +pn{ 1105 | ここは2番目の段落です。 1106 | 2番目以降であれば自由にブロックテキストを挿入できます。 1107 | 以下はコードブロックを挿入する例。 1108 | } 1109 | +code(`aaa`); 1110 | +item{このように、途中で箇条書きを挟むことができます。}< 1111 | +item{当然ネストさせることもできます。}<> 1112 | > 1113 | +pn{ 1114 | 箇条書きを挟んだ後、元の階層に戻って再び段落を再開することができます。 1115 | } 1116 | > 1117 | > 1118 | ```)< 1119 | +itemize(listing-default-label)< 1120 | +item{ここは最初の段落です。ラベルは最初の段落の冒頭に付きます。}< 1121 | +pn{ 1122 | ここは2番目の段落です。 1123 | 2番目以降であれば自由にブロックテキストを挿入できます。 1124 | 以下はコードブロックを挿入する例。 1125 | } 1126 | +code(`aaa`); 1127 | +item{このように、途中で箇条書きを挟むことができます。}< 1128 | +item{当然ネストさせることもできます。}<> 1129 | > 1130 | +pn{ 1131 | 箇条書きを挟んだ後、元の階層に戻って再び段落を再開することができます。 1132 | } 1133 | > 1134 | > 1135 | > 1136 | 1137 | +p{ 1138 | 3つめは、ユーザが自由に箇条書きの項目単位でのコマンドを定義できること。 1139 | } 1140 | 1141 | +code(``` 1142 | % プリアンブルで定義しておく 1143 | let-block +genin it = '< +item?:(text-label{下人「}){#it;」}<> > 1144 | let-block +rouba it = '< +item?:(text-label{老婆「}){#it;」}<> > 1145 | ```); 1146 | 1147 | +example(``` 1148 | +itemize(nofmt)< 1149 | +genin{何をしていた。云え。云わぬと、これだぞよ。} 1150 | +genin{ 1151 | 己は検非違使の庁の役人などではない。 1152 | 今し方この門の下を通りかかった旅の者だ。 1153 | だからお前に縄をかけて、どうしようと云うような事はない。 1154 | ただ、今時分この門の上で、何をして居たのだか、それを己に話しさえすればいいのだ。 1155 | } 1156 | +rouba{ 1157 | この髪を抜いてな、この髪を抜いてな、鬘にしようと思うたのじゃ。 1158 | } 1159 | > 1160 | ```)< 1161 | +itemize(nofmt)< 1162 | +genin{何をしていた。云え。云わぬと、これだぞよ。} 1163 | +genin{ 1164 | 己は検非違使の庁の役人などではない。 1165 | 今し方この門の下を通りかかった旅の者だ。 1166 | だからお前に縄をかけて、どうしようと云うような事はない。 1167 | ただ、今時分この門の上で、何をして居たのだか、それを己に話しさえすればいいのだ。 1168 | } 1169 | +rouba{ 1170 | この髪を抜いてな、この髪を抜いてな、鬘にしようと思うたのじゃ。 1171 | } 1172 | > 1173 | > 1174 | 1175 | % +p{ 1176 | % また、項目の単位がブロックコマンドであるために、 1177 | % ユーザが自由にコマンドを定義できるのもブロックベースの記法の利点です。 1178 | % } 1179 | 1180 | % +p{ 1181 | % これらを応用すれば、定義リストのような箇条書きを実現することもできます。 1182 | % } 1183 | % 1184 | % +example(``` 1185 | % ```)< 1186 | % +itemize(nofmt)< 1187 | % +item?:(description {定義項目1}){これが定義内容です。}<> 1188 | % +item?:(description {ちょっと長めの定義項目2}){ 1189 | % これがちょっと長めの定義内容です。項目だけでなく本文も少しだけ長めです。 1190 | % }<> 1191 | % +item?:(description-newline {だいぶ長いから改行挟んだほうが良い定義項目3}){}< 1192 | % +pn{ 1193 | % こちらは改行を挟んでおり、本文も長めです。 1194 | % このように通常の段落を入れることができます。 1195 | % } 1196 | % > 1197 | % > 1198 | % > 1199 | 1200 | > 1201 | 1202 | +subsection{2つの記法の併用}< 1203 | 1204 | +p{ 1205 | 2つの記法は組み合わせて使用することもできます。 1206 | `+item{}<>` のブロックテキスト中で `+sublist` を用いると、 1207 | ブロックベースの記法内で糖衣構文を導入することができます。 1208 | } 1209 | 1210 | +code(``` 1211 | +itemize(listing-default-label)< 1212 | +item{aaa}<> 1213 | +item{bbb}< 1214 | +sublist(listing-default-label){ 1215 | * bbb の子1 1216 | * bbb の子2 1217 | ** bbb の子2の子1 1218 | } 1219 | > 1220 | +sublist(listing-default-label){ 1221 | * ccc 1222 | ** ccc の子1 1223 | ** ccc の子2 1224 | } 1225 | > 1226 | ```); 1227 | 1228 | +p{ 1229 | `+listing` のインラインテキスト中で `\subitem` を用いると、 1230 | 先程の例とは逆に糖衣構文ベースの記法内でブロックベースの `+item` コマンドなどを用いることができます。 1231 | } 1232 | 1233 | +code(``` 1234 | +listing{ 1235 | * aaa 1236 | * bbb 1237 | \subitem< 1238 | +item{bbb の子1}<> 1239 | +item{bbb の子2}< 1240 | +item{bbb の子2 の子1}<> 1241 | > 1242 | > 1243 | * ccc 1244 | \subitem< 1245 | +item{ccc の子1}<> 1246 | +item{ccc の子2}<> 1247 | > 1248 | } 1249 | ```); 1250 | 1251 | +p{ 1252 | また、糖衣構文ベースの記法の中で糖衣構文ベースの記法を作成できる `\sublist` もあります。 1253 | こちらを用いると、糖衣構文ベースの記法であってもラベルの体裁を変更しつつネストさせることができます。 1254 | } 1255 | 1256 | +code(``` 1257 | +listing{ 1258 | * aaa 1259 | * bbb 1260 | \sublist(listing-default-label){ 1261 | * bbb の子1 1262 | * bbb の子2 1263 | \sublist(listing-default-label){ 1264 | * bbb の子2 の子1 1265 | } 1266 | } 1267 | * ccc 1268 | \sublist(listing-default-label){ 1269 | * ccc の子1 1270 | * ccc の子2 1271 | } 1272 | } 1273 | ```); 1274 | > 1275 | 1276 | +subsection{`enumitem` パッケージにおける箇条書きの等価性}< 1277 | 1278 | +p{ 1279 | `enumitem` パッケージには様々なコマンドが定義されていますが、 1280 | 実はほぼ全てのコマンドは `+item` というコマンドのみを用いて等価に書き表すことができます。 1281 | } 1282 | 1283 | +p{ 1284 | たとえば `+item` コマンドを用いる全ての箇条書きは全て `+itemize` コマンドで囲むことになっていますが、 1285 | 実はこの `+itemize` も `+item` の一種にすぎません。 1286 | 実際、以下の2つのコードは等価です: 1287 | } 1288 | 1289 | +code(``` 1290 | +itemize(bullet)< 1291 | +item{foo bar}<> 1292 | > 1293 | ```); 1294 | 1295 | +code(``` 1296 | +item?:(EnumitemFormat.init)({})?:(bullet)< 1297 | +item{foo bar}<> 1298 | > 1299 | ```); 1300 | 1301 | +p{ 1302 | また、 `+listing` を用いたコードも、 1303 | 実は内部で再帰的に `+item` を用いたインラインテキストへ書き換えるような実装となっています。 1304 | } 1305 | 1306 | +code(``` 1307 | +listing?:(bullet){ 1308 | * foo 1309 | ** foo1 1310 | ** foo2 1311 | * bar 1312 | } 1313 | ```); 1314 | 1315 | +code(``` 1316 | +item?:(EnumitemFormat.init)({})?:(bullet)< 1317 | +item{foo}< 1318 | +item{foo1}<> 1319 | +item{foo2}<> 1320 | > 1321 | +item{bar}<> 1322 | > 1323 | ```); 1324 | 1325 | +p{ 1326 | 更に、インラインテキストの中に子構造を記述できる `\sublist` などのコマンドも、 1327 | 最終的には `+item` を用いた木構造のコードにほぼ等価となるよう実装されています。 1328 | } 1329 | 1330 | +code(``` 1331 | +listing?:(bullet){ 1332 | * foo 1333 | \sublist(dot-arabic){ 1334 | * foo1 1335 | * foo2 1336 | } 1337 | * bar 1338 | \subitem< 1339 | +item{bar1}<> 1340 | +item{bar2}<> 1341 | > 1342 | } 1343 | ```); 1344 | 1345 | +code(``` 1346 | +item?:(EnumitemFormat.init)({})?:(bullet)< 1347 | +item{foo}< 1348 | +item?:(dot-arabic){foo1}<> 1349 | +item?:(dot-arabic){foo2}<> 1350 | > 1351 | +item{bar}< 1352 | +item{bar1}<> 1353 | +item{bar2}<> 1354 | > 1355 | > 1356 | ```); 1357 | 1358 | > 1359 | 1360 | > 1361 | 1362 | 1363 | +section{機能一覧}< 1364 | 1365 | +subsection{`Enumitem` モジュール}< 1366 | 1367 | +p{ 1368 | `Enumitem` モジュールは本パッケージの根幹となるコマンドを定義します。 1369 | 最も大切なのは `+item` コマンドであり、上で述べたように 1370 | `Enumitem` パッケージで提供される主要なコマンドは 1371 | ほとんど `+item` を用いたブロックボックス列に展開される仕組みになっています。 1372 | `+item` は以下の引数を取ります。 1373 | } 1374 | 1375 | +code(``` 1376 | +item?:( itemfmt-self )({ text-body })?:( itemfmt-child )< children > 1377 | ```); 1378 | 1379 | +p{引数の詳細は以下のとおりです。} 1380 | 1381 | +block-frame< 1382 | +description< 1383 | 1384 | +param{itemfmt-self}{`itemfmt`、オプション}< 1385 | +pn{ 1386 | 自分自身の項目の体裁。 1387 | 省略した場合は、自身の親で設定されたフォーマットが用いられる。 1388 | あくまで自分自身の項目のみに影響があり、後述の通り、自身の子要素には反映されない。 1389 | } 1390 | > 1391 | 1392 | +param{text-body}{`inline-text`、必須}< 1393 | +pn{ 1394 | 自分自身の項目の本文。ラベルは本文の左端に付く。 1395 | 空のインラインテキストを指定することもできる。 1396 | その場合はフォーマットの `display-label-with-empty-body` オプションによってラベルが付くかどうか変化する。 1397 | } 1398 | > 1399 | 1400 | +param{itemfmt-child}{`itemfmt`、オプション}< 1401 | +pn{ 1402 | 子要素の項目の体裁のデフォルト値。省略した場合、 1403 | 子要素は自身の親で設定されたフォーマットを引き継ぐ(`itemfmt-self` の値は用いられない)。 1404 | } 1405 | > 1406 | 1407 | +param{children}{`block-text`、必須}< 1408 | +pn{ 1409 | 子要素の項目。空のブロックテキストを指定することもでき、その場合は `block-nil` と同等の扱いとなる。 1410 | } 1411 | > 1412 | 1413 | > 1414 | > 1415 | 1416 | > 1417 | 1418 | +subsection{`itemfmt` 型}< 1419 | 1420 | +p{ 1421 | `itemfmt` 型は `enumitem` パッケージで定義されている最も重要な型であり、 1422 | 箇条書きの体裁の全てを決定づけるものです。 1423 | `itemfmt` 型は `context -> int list -> itemconfig` 型のエイリアスであり、 1424 | 現在のテキスト処理文脈と、対象となる項目のインデックスの列を与えたときに 1425 | ラベルの体裁やインデント量といった設定値をまとめたレコードを返すような関数です。 1426 | `itemconfig` は以下のフィールドを持つレコードとなっています。 1427 | } 1428 | 1429 | +block-frame< 1430 | +description< 1431 | 1432 | +param{indent}{`length -> length`}< 1433 | +pn{ 1434 | 左側のインデント量を与える関数。より具体的には、 1435 | 「`label` フィールドの値で決定されるラベルのボックスの横幅を与え、インデント量を返す関数」。 1436 | 項目の本文は(ラベルの付与される先頭の行を除き)全てここで決定される長さだけインデントされる。 1437 | たとえば恒等写像 `(fun len -> len)` を与えると、箇条書きの本文はラベルの長さだけインデントされる。 1438 | } 1439 | > 1440 | 1441 | +param{indent-right}{`length`}< 1442 | +pn{ 1443 | 右側のインデント量。 1444 | } 1445 | > 1446 | 1447 | +param{label}{`inline-boxes`}< 1448 | +pn{ 1449 | ラベルを表すインラインボックス列。 1450 | } 1451 | > 1452 | 1453 | +param{label-with-empty-body}{`labelwithemptybody`}< 1454 | +pn{ 1455 | 項目の中身(項目の直後に続くインラインテキスト)が空だったとき、その項目をどのように描くか。 1456 | `labelwithemptybody` は以下の3つの定数ヴァリアントからなる代数的データ型である。 1457 | } 1458 | 1459 | +dd{LabelDisplay}{テキストが空でも構わずにラベルを描画する。} 1460 | +dd{LabelInherit}{自身はラベルを描画せず、自身の空でない子項目があればそこで一緒に描画させてもらう。} 1461 | +dd{LabelIgnore}{ラベルを描かず、継承もしない。} 1462 | > 1463 | 1464 | +param{margin-top}{`length`}< 1465 | +pn{ 1466 | 箇条書きの段落の上に追加であける余白。ただし、 1467 | \SATySFi; 標準の機能で設けられる段落間空白はこれと独立に挿入される。 1468 | } 1469 | > 1470 | 1471 | +param{margin-bottom}{`length`}< 1472 | +pn{ 1473 | 箇条書きの段落の下に追加であける余白。ただし、 1474 | \SATySFi; 標準の機能で設けられる段落間空白はこれと独立に挿入される。 1475 | } 1476 | > 1477 | 1478 | +param{context-body}{`context`}< 1479 | +pn{ 1480 | テキスト処理文脈。 1481 | ラベル以外の全ての本文が与えられた関数によって変換される。 1482 | } 1483 | > 1484 | 1485 | > 1486 | > 1487 | 1488 | > 1489 | 1490 | > 1491 | 1492 | > 1493 | -------------------------------------------------------------------------------- /satysfi-enumitem-doc.opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | name: "satysfi-enumitem-doc" 3 | version: "3.0.1" 4 | synopsis: "A SATySFi package for creating itemized lists" 5 | description: """A SATySFi package for creating itemized lists.""" 6 | 7 | maintainer: "Shinichi Mogami " 8 | authors: "Shinichi Mogami " 9 | license: "MIT" 10 | homepage: "https://github.com/monaqa/satysfi-enumitem" 11 | bug-reports: "https://github.com/monaqa/satysfi-enumitem/issues" 12 | dev-repo: "git+https://github.com/monaqa/satysfi-enumitem.git" 13 | 14 | depends: [ 15 | "satysfi" {>= "0.0.6" & < "0.0.7"} 16 | "satyrographos" {>= "0.0.2" & < "0.0.3"} 17 | "satysfi-dist" 18 | "satysfi-enumitem" {= "%{version}%"} 19 | ] 20 | build: [ 21 | ["satyrographos" "opam" "build" 22 | "-name" "enumitem-doc" 23 | "-prefix" "%{prefix}%" 24 | "-script" "%{build}%/Satyristes"] 25 | ] 26 | install: [ 27 | ["satyrographos" "opam" "install" 28 | "-name" "enumitem-doc" 29 | "-prefix" "%{prefix}%" 30 | "-script" "%{build}%/Satyristes"] 31 | ] 32 | 33 | -------------------------------------------------------------------------------- /satysfi-enumitem.opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | name: "satysfi-enumitem" 3 | version: "3.0.1" 4 | synopsis: "A SATySFi package for creating itemized lists" 5 | description: """A SATySFi package for creating itemized lists.""" 6 | 7 | maintainer: "Shinichi Mogami " 8 | authors: "Shinichi Mogami " 9 | license: "MIT" 10 | homepage: "https://github.com/monaqa/satysfi-enumitem" 11 | bug-reports: "https://github.com/monaqa/satysfi-enumitem/issues" 12 | dev-repo: "git+https://github.com/monaqa/satysfi-enumitem.git" 13 | 14 | depends: [ 15 | "satysfi" {>= "0.0.6" & < "0.0.7"} 16 | "satyrographos" {>= "0.0.2" & < "0.0.3"} 17 | "satysfi-dist" 18 | "satysfi-base" {>="1.0.0" & < "2.0.0"} 19 | ] 20 | build: [ ] 21 | install: [ 22 | ["satyrographos" "opam" "install" 23 | "-name" "enumitem" 24 | "-prefix" "%{prefix}%" 25 | "-script" "%{build}%/Satyristes"] 26 | ] 27 | -------------------------------------------------------------------------------- /src/counter.satyh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monaqa/satysfi-enumitem/f2444a530aa2082d912d9ffdc45341639c9d3b54/src/counter.satyh -------------------------------------------------------------------------------- /src/enumitem.satyh: -------------------------------------------------------------------------------- 1 | @require: base/option-ext 2 | @require: base/typeset/base 3 | @require: base/length 4 | @require: base/tuple 5 | @import: ./param 6 | @import: ./itemfmt 7 | 8 | type itemfmt = context -> int list -> itemconfig 9 | 10 | module Enumitem : sig 11 | 12 | % val spaced-itemfmt: length -> context -> itemconfig 13 | % val nofmt: length -> context -> itemconfig 14 | 15 | direct +item : [(context -> int list -> itemconfig)?; inline-text; (context -> int list -> itemconfig)?; block-text] block-cmd 16 | direct +itemize : [context -> int list -> itemconfig; block-text] block-cmd 17 | direct \itemize : [context -> int list -> itemconfig; block-text] inline-cmd 18 | direct \sublist: [context -> int list -> itemconfig; itemize] inline-cmd 19 | direct +sublist: [context -> int list -> itemconfig; itemize] block-cmd 20 | direct \subitem: [block-text] inline-cmd 21 | 22 | val \embed-block: [block-text] inline-cmd 23 | 24 | end = struct 25 | 26 | let-mutable counter-stack <- [] 27 | let-mutable label-stack <- [] 28 | 29 | let display-counter () = 30 | let-rec aux s lst = match lst with 31 | | [] -> ` ` 32 | | x :: rest -> ((arabic x) ^ #` `# ^ (aux s rest)) 33 | in 34 | `counter:` ^ (aux ` ` !counter-stack) |> display-message 35 | 36 | let push-counter () = counter-stack <- 0 :: !counter-stack 37 | let push-label label indent = label-stack <- (label, indent) :: !label-stack 38 | 39 | let inc-counter n = counter-stack <- ( 40 | match !counter-stack with 41 | | [] -> [] 42 | | x :: rest -> (x + n) :: rest 43 | ) 44 | let pop-counter () = counter-stack <- ( 45 | match !counter-stack with 46 | | [] -> [] 47 | | x :: rest -> rest 48 | ) 49 | 50 | let get-all-label () = 51 | let label-with-margin (label, indent) = 52 | let (wid, h, d) = get-natural-metrics label in 53 | inline-graphics wid h d (fun pt -> [ draw-text pt label ]) 54 | in 55 | !label-stack |> List.reverse |> List.map label-with-margin |> List.fold-left (++) inline-nil 56 | let get-all-indent () = 57 | !label-stack |> List.map Pair.snd |> List.fold-left (+') 0pt 58 | let reset-labels () = label-stack <- [] 59 | let pop-labels () = 60 | let label = get-all-label () in 61 | let indent = get-all-indent () in 62 | let () = reset-labels () in 63 | (label, indent) 64 | 65 | let set-counter n = counter-stack <- ( 66 | match !counter-stack with 67 | | [] -> [] 68 | | x :: rest -> n :: rest 69 | ) 70 | let-inline \set-counter n = let () = set-counter n in {} 71 | 72 | let sublist-stack = EnumitemParam.make '<> 73 | 74 | let empty-deco _ _ _ _ = [] 75 | let empty-decoset = (empty-deco, empty-deco, empty-deco, empty-deco) 76 | 77 | let no-pad = (0pt, 0pt, 0pt, 0pt) 78 | 79 | let current-itemfmt = EnumitemParam.make EnumitemFormat.init 80 | 81 | let-block ctx +item ?:itemfmt it ?:itemfmt-children inner = 82 | let itemfmt = itemfmt |> Option.from (EnumitemParam.get current-itemfmt) in 83 | 84 | let () = inc-counter 1 in 85 | 86 | let record = itemfmt ctx !counter-stack in 87 | let ib-label = record#label in 88 | let (wid-label, ht-label, dp-label) = get-natural-metrics ib-label in 89 | let indent = record#indent wid-label in 90 | 91 | let bbf ctx = 92 | let ctx = record#context-body ctx in 93 | 94 | let () = sublist-stack |> EnumitemParam.discard in 95 | let ib = read-inline ctx it in 96 | let bt-inner-additional = sublist-stack |> EnumitemParam.get in 97 | 98 | let bb-body = 99 | let (w, h, d) = get-natural-metrics ib in 100 | match (Length.(w == 0pt && h == 0pt && d == 0pt), record#label-with-empty-body) with 101 | | (false, _) -> % 本文がある場合。 102 | let () = push-label ib-label indent in 103 | let (ib-label-all, indent-all) = pop-labels () in 104 | let ib-label-with-skip = 105 | inline-skip (0pt -' indent-all) ++ ib-label-all 106 | in 107 | line-break true true ctx ( 108 | ib-label-with-skip ++ ib ++ inline-fil 109 | ) 110 | | (true, LabelDisplay) -> % 本文がないがかまわずラベルを描画してほしい場合。 111 | % length != 0pt のときに同じ。 2度書かなくて良い文法がほしい 112 | let () = push-label ib-label indent in 113 | let (ib-label-all, indent-all) = pop-labels () in 114 | let ib-label-with-skip = 115 | inline-skip (0pt -' indent-all) ++ ib-label-all 116 | in 117 | line-break true true ctx ( 118 | ib-label-with-skip ++ ib ++ inline-fil 119 | ) 120 | | (true, LabelInherit) -> 121 | let () = push-label ib-label indent in 122 | block-nil 123 | | (true, LabelIgnore) -> 124 | block-nil 125 | in 126 | 127 | let bb-inner = 128 | 129 | % 事前に起こしておく副作用 130 | let () = push-counter () in 131 | let current-itemfmt-old = EnumitemParam.get current-itemfmt in 132 | let () = match itemfmt-children with 133 | | Some(fmt) -> current-itemfmt |> EnumitemParam.set fmt 134 | | None -> () 135 | in 136 | 137 | % read-block 138 | let bb-inner = read-block ctx '<#bt-inner-additional;#inner;> in 139 | 140 | % 起こした副作用の後片付け 141 | let () = pop-counter () in 142 | let () = current-itemfmt |> EnumitemParam.set current-itemfmt-old in 143 | 144 | if Length.(get-natural-length bb-inner == 0pt) then 145 | block-nil 146 | else 147 | block-frame-breakable ctx (0pt, 0pt, record#margin-top, record#margin-bottom) 148 | empty-decoset (fun ctx -> bb-inner) 149 | in 150 | let () = reset-labels () in 151 | bb-body +++ bb-inner 152 | in 153 | block-frame-breakable ctx (indent, record#indent-right, 0pt, 0pt) empty-decoset bbf 154 | 155 | let-inline ctx \embed-block bt = 156 | let ib-block = embed-block-breakable ctx (read-block ctx '<#bt;>) in 157 | inline-fil ++ ib-block ++ omit-skip-after 158 | 159 | let-block +itemize itemfmt bt = 160 | '< +item?:(EnumitemFormat.init)({})?:(itemfmt)(bt); > 161 | 162 | let-rec convert-item-to-bt itemfmt (Item(it, children)) = 163 | let bt-children = 164 | children |> List.map (convert-item-to-bt itemfmt) 165 | |> List.fold-left (fun bt1 bt2 -> '<#bt1;#bt2;>) '<> 166 | in 167 | '< +item?:(itemfmt)(it)(bt-children); > 168 | 169 | let-inline \itemize itemfmt bt = {\embed-block<+itemize(itemfmt)(bt);>} 170 | 171 | let-inline ctx \sublist itemfmt (Item(_, children)) = 172 | let bt-children = 173 | children |> List.map (convert-item-to-bt itemfmt) 174 | |> List.fold-left (fun bt1 bt2 -> '<#bt1;#bt2;>) '<> 175 | in 176 | let () = sublist-stack |> EnumitemParam.set bt-children in 177 | inline-nil 178 | 179 | let-block +sublist itemfmt (Item(_, children)) = 180 | children |> List.map (convert-item-to-bt itemfmt) 181 | |> List.fold-left (fun bt1 bt2 -> '<#bt1;#bt2;>) '<> 182 | 183 | let-inline ctx \subitem bt = 184 | let () = sublist-stack |> EnumitemParam.set bt in 185 | inline-nil 186 | 187 | end 188 | 189 | module EnumitemFormatUtil : sig 190 | 191 | % text mapping function 192 | val to-arabic: int -> inline-text 193 | val to-roman : int -> inline-text 194 | val to-Roman : int -> inline-text 195 | val to-alph : int -> inline-text 196 | val to-Alph : int -> inline-text 197 | 198 | % index decolation function (ordered) 199 | val raw : (int -> inline-text) -> context -> int -> inline-boxes 200 | val dot : (int -> inline-text) -> context -> int -> inline-boxes 201 | val paren : (int -> inline-text) -> context -> int -> inline-boxes 202 | val bracket : (int -> inline-text) -> context -> int -> inline-boxes 203 | 204 | % index decolation function (unordered) 205 | val shape-bullet : context -> inline-boxes 206 | val shape-white-bullet : context -> inline-boxes 207 | 208 | % adjuster 209 | val align-right: length -> inline-boxes -> inline-boxes 210 | 211 | end = struct 212 | 213 | % text mapping 214 | 215 | let num-to-roman-char capital num = 216 | let unic-point = match num with 217 | | 1 -> 0x0049 % `I` 218 | | 5 -> 0x0056 % `V` 219 | | 10 -> 0x0058 % `X` 220 | | _ -> 0x003F % `?` 221 | in 222 | if capital then unic-point else unic-point + 0x20 223 | 224 | let roman-seq num = match num with 225 | | 1 -> [ 1; ] % i 226 | | 2 -> [ 1; 1; ] % ii 227 | | 3 -> [ 1; 1; 1; ] % iii 228 | | 4 -> [ 1; 5; ] % iv 229 | | 5 -> [ 5; ] % v 230 | | 6 -> [ 5; 1; ] % vi 231 | | 7 -> [ 5; 1; 1; ] % vii 232 | | 8 -> [ 5; 1; 1; 1; ] % viii 233 | | 9 -> [ 1; 10; ] % ix 234 | | 10 -> [10; ] % x 235 | | 11 -> [10; 1; ] % xi 236 | | 12 -> [10; 1; 1; ] % xii 237 | | 13 -> [10; 1; 1; 1; ] % xiii 238 | | 14 -> [10; 1; 5; ] % xiv 239 | | 15 -> [10; 5; ] % xv 240 | | 16 -> [10; 5; 1; ] % xvi 241 | | 17 -> [10; 5; 1; 1; ] % xvii 242 | | 18 -> [10; 5; 1; 1; 1; ] % xviii 243 | | 19 -> [10; 1; 10; ] % xix 244 | | 20 -> [10; 10; ] % xx 245 | | 21 -> [10; 10; 1; ] % xxi 246 | | 22 -> [10; 10; 1; 1; ] % xxii 247 | | 23 -> [10; 10; 1; 1; 1; ] % xxiii 248 | | 24 -> [10; 10; 1; 5; ] % xxiv 249 | | 25 -> [10; 10; 5; ] % xxv 250 | | _ -> [ 0; 0; ] % ?? 251 | 252 | let to-arabic num = embed-string (arabic num) 253 | 254 | let to-roman num = 255 | embed-string 256 | (string-unexplode 257 | (List.map (fun i -> num-to-roman-char false i) (roman-seq num))) 258 | let to-Roman num = 259 | embed-string 260 | (string-unexplode 261 | (List.map (fun i -> num-to-roman-char true i) (roman-seq num))) 262 | 263 | let to-alph num = embed-string (string-unexplode [num + 0x0060;]) 264 | let to-Alph num = embed-string (string-unexplode [num + 0x0040;]) 265 | 266 | % index decolation function (ordered) 267 | 268 | let raw num-format ctx idx = 269 | let it-num = num-format idx in 270 | let ib-label = read-inline ctx {#it-num;} in 271 | let (wid-label, _, _) = get-natural-metrics ib-label in 272 | ib-label 273 | 274 | let dot num-format ctx idx = 275 | let it-num = num-format idx in 276 | let ib-label = read-inline ctx {#it-num;.} in 277 | let (wid-label, _, _) = get-natural-metrics ib-label in 278 | ib-label 279 | 280 | let paren num-format ctx idx = 281 | let it-num = num-format idx in 282 | let ib-label = read-inline ctx {(#it-num;)} in 283 | let (wid-label, _, _) = get-natural-metrics ib-label in 284 | ib-label 285 | 286 | let bracket num-format ctx idx = 287 | let it-num = num-format idx in 288 | let ib-label = read-inline ctx {[#it-num;]} in 289 | let (wid-label, _, _) = get-natural-metrics ib-label in 290 | ib-label 291 | 292 | % index decolation function (unordered) 293 | 294 | let shape-bullet ctx = 295 | let font-size = get-font-size ctx in 296 | let interval = font-size *' 0.3 in 297 | let circ ctx (x, y) = 298 | let cx = x +' font-size -' (font-size *' 0.3) -' interval in 299 | let cy = y +' font-size *' 0.3 in 300 | let r = font-size *' 0.15 in 301 | Gr.circle (cx, cy) r 302 | in 303 | inline-graphics font-size (font-size *' 0.5) 0pt 304 | (fun (x, y) -> [fill Color.black (circ ctx (x, y))]) 305 | 306 | let shape-white-bullet ctx = 307 | let font-size = get-font-size ctx in 308 | let interval = font-size *' 0.3 in 309 | let circ ctx (x, y) = 310 | let cx = x +' font-size -' (font-size *' 0.3) -' interval in 311 | let cy = y +' font-size *' 0.3 in 312 | let r = font-size *' 0.12 in 313 | Gr.circle (cx, cy) r 314 | in 315 | inline-graphics font-size (font-size *' 0.5) 0pt 316 | (fun (x, y) -> [stroke 0.8pt Color.black (circ ctx (x, y))]) 317 | 318 | % adjuster 319 | let align-right wid ib = 320 | let (wid-ib, ht, dp) = get-natural-metrics ib in 321 | inline-graphics wid ht dp (fun (x, y) -> [draw-text (x +' wid -' wid-ib, y) ib]) 322 | end 323 | 324 | 325 | module EnumitemAlias : sig 326 | 327 | % default label 328 | val nofmt : context -> int list -> itemconfig 329 | 330 | % label (ordered list) 331 | val raw-arabic : context -> int list -> itemconfig 332 | val dot-arabic : context -> int list -> itemconfig 333 | val paren-arabic : context -> int list -> itemconfig 334 | val bracket-arabic : context -> int list -> itemconfig 335 | val raw-roman : context -> int list -> itemconfig 336 | val dot-roman : context -> int list -> itemconfig 337 | val paren-roman : context -> int list -> itemconfig 338 | val bracket-roman : context -> int list -> itemconfig 339 | val raw-Roman : context -> int list -> itemconfig 340 | val dot-Roman : context -> int list -> itemconfig 341 | val paren-Roman : context -> int list -> itemconfig 342 | val bracket-Roman : context -> int list -> itemconfig 343 | val raw-alph : context -> int list -> itemconfig 344 | val dot-alph : context -> int list -> itemconfig 345 | val paren-alph : context -> int list -> itemconfig 346 | val bracket-alph : context -> int list -> itemconfig 347 | val raw-Alph : context -> int list -> itemconfig 348 | val dot-Alph : context -> int list -> itemconfig 349 | val paren-Alph : context -> int list -> itemconfig 350 | val bracket-Alph : context -> int list -> itemconfig 351 | 352 | val dot-arabic-rec : context -> int list -> itemconfig 353 | 354 | % label (unordered list) 355 | 356 | val bullet: context -> int list -> itemconfig 357 | val white-bullet: context -> int list -> itemconfig 358 | 359 | % label (definition list) 360 | val description: (inline-text -> inline-text)?-> inline-text -> context -> int list -> itemconfig 361 | 362 | % label (versatile) 363 | % ラベルとなるインラインテキストを与えて箇条書きを作成する。 364 | val text-label : inline-text -> context -> int list -> itemconfig 365 | val index-label : (int -> inline-text) -> context -> int list -> itemconfig 366 | val with-depth : (context -> int list -> itemconfig) list -> context -> int list -> itemconfig 367 | 368 | % listing command 369 | val listing-default-label: context -> int list -> itemconfig 370 | val enumerate-default-label: context -> int list -> itemconfig 371 | 372 | direct +listing : [(context -> int list -> itemconfig)?; itemize] block-cmd 373 | direct +enumerate: [(context -> int list -> itemconfig)?; itemize] block-cmd 374 | direct \listing : [(context -> int list -> itemconfig)?; itemize] inline-cmd 375 | direct \enumerate: [(context -> int list -> itemconfig)?; itemize] inline-cmd 376 | 377 | direct +description: [block-text] block-cmd 378 | val +ditem: [(inline-text -> inline-text)?; inline-text; inline-text; block-text] block-cmd 379 | 380 | end = struct 381 | 382 | open EnumitemFormat 383 | 384 | let nofmt = init 385 | 386 | % versatile label 387 | let id x = x 388 | 389 | let text-label it ctx _ = (| 390 | indent = id; 391 | indent-right = 0pt; 392 | label = (read-inline ctx it); 393 | label-with-empty-body = LabelIgnore; 394 | margin-top = 0pt; 395 | margin-bottom = 0pt; 396 | context-body = id; 397 | |) 398 | 399 | let index-label itf ctx idxlst = 400 | let it = match idxlst with 401 | | [] -> itf 0 402 | | idx :: _ -> itf idx 403 | in 404 | (| 405 | indent = id; 406 | indent-right = 0pt; 407 | label = (read-inline ctx it); 408 | label-with-empty-body = LabelIgnore; 409 | margin-top = 0pt; 410 | margin-bottom = 0pt; 411 | context-body = id; 412 | |) 413 | 414 | let with-depth labellst ctx idxlst = 415 | let len-cycle = labellst |> List.length in 416 | let label = 417 | if len-cycle == 0 then 418 | init 419 | else 420 | labellst |> List.nth (((idxlst |> List.length) - 1) mod len-cycle) 421 | |> Option.from init 422 | in 423 | label ctx idxlst 424 | 425 | % formats 426 | let enum-format enumeratef = 427 | let labelf ctx idx = 428 | let fsizer r = get-font-size ctx *' r in 429 | (enumeratef ctx idx |> EnumitemFormatUtil.align-right (fsizer 1.5)) 430 | ++ inline-skip (fsizer 0.5) 431 | in 432 | EnumitemFormat.new-ordered labelf 433 | 434 | let raw-arabic = enum-format EnumitemFormatUtil.(raw to-arabic) 435 | let dot-arabic = enum-format EnumitemFormatUtil.(dot to-arabic) 436 | let paren-arabic = enum-format EnumitemFormatUtil.(paren to-arabic) 437 | let bracket-arabic = enum-format EnumitemFormatUtil.(bracket to-arabic) 438 | 439 | let raw-roman = enum-format EnumitemFormatUtil.(raw to-roman) 440 | let dot-roman = enum-format EnumitemFormatUtil.(dot to-roman) 441 | let paren-roman = enum-format EnumitemFormatUtil.(paren to-roman) 442 | let bracket-roman = enum-format EnumitemFormatUtil.(bracket to-roman) 443 | 444 | let raw-Roman = enum-format EnumitemFormatUtil.(raw to-Roman) 445 | let dot-Roman = enum-format EnumitemFormatUtil.(dot to-Roman) 446 | let paren-Roman = enum-format EnumitemFormatUtil.(paren to-Roman) 447 | let bracket-Roman = enum-format EnumitemFormatUtil.(bracket to-Roman) 448 | 449 | let raw-alph = enum-format EnumitemFormatUtil.(raw to-alph) 450 | let dot-alph = enum-format EnumitemFormatUtil.(dot to-alph) 451 | let paren-alph = enum-format EnumitemFormatUtil.(paren to-alph) 452 | let bracket-alph = enum-format EnumitemFormatUtil.(bracket to-alph) 453 | 454 | let raw-Alph = enum-format EnumitemFormatUtil.(raw to-Alph) 455 | let dot-Alph = enum-format EnumitemFormatUtil.(dot to-Alph) 456 | let paren-Alph = enum-format EnumitemFormatUtil.(paren to-Alph) 457 | let bracket-Alph = enum-format EnumitemFormatUtil.(bracket to-Alph) 458 | 459 | let dot-arabic-rec ctx idxlst = 460 | let indentf wid-label = 461 | Length.max (get-font-size ctx *' 1.5) (wid-label +' get-font-size ctx *' 1.0) 462 | in 463 | let label = 464 | idxlst |> List.map arabic |> List.map embed-string 465 | |> List.fold-left (fun it1 it2 -> {#it2;.#it1;}) {} 466 | |> read-inline ctx 467 | in 468 | (| 469 | (EnumitemFormat.init ctx idxlst) with 470 | indent = indentf; 471 | label = label ++ inline-skip (get-font-size ctx *' 0.5); 472 | |) 473 | 474 | let-inline ctx \hskip wid-ratio = 475 | let l = get-font-size ctx *' wid-ratio in 476 | inline-skip l 477 | 478 | let bullet = 479 | text-label 480 | {\hskip(0.5);\eval(EnumitemFormatUtil.shape-bullet);} 481 | 482 | let white-bullet = 483 | text-label 484 | {\hskip(0.5);\eval(EnumitemFormatUtil.shape-white-bullet);} 485 | 486 | % command 487 | 488 | let listing-default-label ctx idxlst = 489 | match List.length idxlst mod 2 with 490 | | 1 -> bullet ctx idxlst 491 | | _ -> white-bullet ctx idxlst 492 | 493 | let enumerate-default-label ctx idxlst = 494 | match List.length idxlst mod 3 with 495 | | 1 -> dot-arabic ctx idxlst 496 | | 2 -> paren-alph ctx idxlst 497 | | _ -> paren-roman ctx idxlst 498 | 499 | let-rec convert-item-to-bt (Item(it, children)) = 500 | let bt-children = 501 | children |> List.map convert-item-to-bt 502 | |> List.fold-left (fun bt1 bt2 -> '<#bt1;#bt2;>) '<> 503 | in 504 | '< +item(it)(bt-children); > 505 | 506 | let-block ctx +listing ?:itemfmt (Item(_, children)) = 507 | let itemfmt = itemfmt |> Option.from listing-default-label in 508 | let bt-children = 509 | children |> List.map convert-item-to-bt 510 | |> List.fold-left (fun bt1 bt2 -> '<#bt1;#bt2;>) '<> 511 | in 512 | read-block ctx '< 513 | +itemize(itemfmt)(bt-children); 514 | > 515 | 516 | let-inline ctx \listing ?:itemfmt items = 517 | let itemfmt = itemfmt |> Option.from listing-default-label in 518 | read-inline ctx {\Enumitem.embed-block<+listing?:(itemfmt)(items);>} 519 | 520 | let-block ctx +enumerate ?:itemfmt (Item(_, children)) = 521 | let itemfmt = itemfmt |> Option.from enumerate-default-label in 522 | let bt-children = 523 | children |> List.map convert-item-to-bt 524 | |> List.fold-left (fun bt1 bt2 -> '<#bt1;#bt2;>) '<> 525 | in 526 | read-block ctx '< 527 | +itemize(itemfmt)(bt-children); 528 | > 529 | 530 | let-inline ctx \enumerate ?:itemfmt items = 531 | let itemfmt = itemfmt |> Option.from enumerate-default-label in 532 | read-inline ctx {\Enumitem.embed-block<+enumerate?:(itemfmt)(items);>} 533 | 534 | % description 535 | let description ?:itf it ctx _ = 536 | let fsizer r = get-font-size ctx *' r in 537 | let itf = itf |> Option.from (fun x -> x) in 538 | let indent wid-label = 539 | Length.min (get-font-size ctx *' 6.0) wid-label 540 | in 541 | let label = 542 | let ib = read-inline ctx (itf it) in 543 | let (wid, _, _) = get-natural-metrics ib in 544 | ib ++ inline-skip (Length.max (fsizer 1.0) (fsizer 2.0 -' wid)) 545 | in 546 | (| 547 | (EnumitemFormat.init ctx []) with 548 | indent = (fun _ -> get-font-size ctx *' 2.0); 549 | label = label; 550 | label-with-empty-body = LabelDisplay; 551 | |) 552 | 553 | % let description-newline ?:itf it ctx _ = 554 | % let itf = itf |> Option.from (fun x -> x) in 555 | % let label = 556 | % let fsizer r = get-font-size ctx *' r in 557 | % let ib = read-inline ctx (itf it) in 558 | % let (wid, _, _) = get-natural-metrics ib in 559 | % ib ++ inline-skip (Length.max (fsizer 1.0) (fsizer 2.0 -' wid)) 560 | % in 561 | % (| 562 | % (EnumitemFormat.init ctx []) with 563 | % indent = (fun _ -> get-font-size ctx *' 2.0); 564 | % label = label; 565 | % label-with-empty-body = LabelDisplay; 566 | % |) 567 | 568 | let-block +description bt = '< +itemize(nofmt)(bt); > 569 | 570 | let-block ctx +ditem ?:itf dt it-dd bt-dd = 571 | let itf = itf |> Option.from (fun x -> x) in 572 | let itemfmtf = description ?:itf in 573 | read-block ctx '< 574 | +item?:(itemfmtf dt)(it-dd)(bt-dd); 575 | > 576 | 577 | end 578 | -------------------------------------------------------------------------------- /src/itemfmt.satyh: -------------------------------------------------------------------------------- 1 | @require: base/list-ext 2 | @require: base/length 3 | @require: base/color-ext 4 | @require: gr 5 | 6 | type labelwithemptybody = 7 | | LabelDisplay % テキストが空でもかまわずラベルを描画する。 8 | | LabelInherit % ラベルは描画せず、自身の子要素があればそこでラベルを一緒に描画してもらう。 9 | | LabelIgnore % ラベルを描かず、継承もしない。 10 | 11 | type itemconfig = (| 12 | % 基準となる左側のインデント量。 13 | % args: 14 | % label-width (length): ラベルの幅。 15 | % 16 | % たとえば (fun x -> x) を指定すれば本文のインデントがラベルの右幅に一致する。 17 | indent: length -> length; 18 | 19 | % 右側のインデント量。 20 | indent-right: length; 21 | 22 | % 現在のアイテムのインデックスを与えて、ラベルのインラインボックス列を返す。 23 | label: inline-boxes; 24 | 25 | % ラベルに対応するテキストが空のとき、ラベルの描画をどのように行うか。 26 | label-with-empty-body: labelwithemptybody; 27 | 28 | % 箇条書きの段落の上に追加であける余白(paragraph-margin による余白はそのまま入る)。 29 | margin-top: length; 30 | 31 | % 箇条書きの段落の下に追加であける余白(paragraph-margin による余白はそのまま入る)。 32 | margin-bottom: length; 33 | 34 | % 中身の context を変換する関数。 35 | context-body: (context -> context); 36 | |) 37 | 38 | module EnumitemFormat : sig 39 | 40 | % builder 41 | val init : context -> int list -> itemconfig 42 | val default : itemconfig 43 | 44 | val new : (context -> int list -> inline-boxes) -> context -> int list -> itemconfig 45 | 46 | val new-unordered : (context -> inline-boxes) -> context -> int list -> itemconfig 47 | val new-unordered-with-depth : (context -> int -> inline-boxes) -> context -> int list -> itemconfig 48 | val new-ordered : (context -> int -> inline-boxes) -> context -> int list -> itemconfig 49 | val new-description : length?-> (inline-text -> inline-text) -> inline-text -> context -> int list -> itemconfig 50 | 51 | val set-indent : (context -> length -> length) -> (context -> int list -> itemconfig) -> context -> int list -> itemconfig 52 | val set-context-body : (context -> int list -> context) -> (context -> int list -> itemconfig) -> context -> int list -> itemconfig 53 | val set-label-display: (context -> int list -> itemconfig) -> context -> int list -> itemconfig 54 | val set-label-inherit: (context -> int list -> itemconfig) -> context -> int list -> itemconfig 55 | val set-label-ignore : (context -> int list -> itemconfig) -> context -> int list -> itemconfig 56 | 57 | end = struct 58 | 59 | let id x = x 60 | 61 | let default = (| 62 | indent = (fun _ -> 0pt); 63 | indent-right = 0pt; 64 | label = inline-nil; 65 | label-with-empty-body = LabelIgnore; 66 | margin-top = 0pt; 67 | margin-bottom = 0pt; 68 | context-body = id; 69 | |) 70 | 71 | let init _ _ = default 72 | 73 | let new-unordered labelf ctx _ = 74 | (| 75 | indent = id; 76 | indent-right = 0pt; 77 | label = labelf ctx; 78 | label-with-empty-body = LabelIgnore; 79 | margin-top = 0pt; 80 | margin-bottom = 0pt; 81 | context-body = id; 82 | |) 83 | 84 | let new-unordered-with-depth labelf ctx idxlst = 85 | (| 86 | indent = id; 87 | indent-right = 0pt; 88 | label = labelf ctx (List.length idxlst); 89 | label-with-empty-body = LabelIgnore; 90 | margin-top = 0pt; 91 | margin-bottom = 0pt; 92 | context-body = id; 93 | |) 94 | 95 | let new-ordered labelf ctx idxlst = 96 | let label = match idxlst with 97 | | [] -> labelf ctx 0 98 | | idx :: _ -> labelf ctx idx 99 | in 100 | (| 101 | indent = id; 102 | indent-right = 0pt; 103 | label = label; 104 | label-with-empty-body = LabelInherit; 105 | margin-top = 0pt; 106 | margin-bottom = 0pt; 107 | context-body = id; 108 | |) 109 | 110 | let new labelf ctx idxlst = 111 | (| 112 | indent = id; 113 | indent-right = 0pt; 114 | label = labelf ctx idxlst; 115 | label-with-empty-body = LabelIgnore; 116 | margin-top = 0pt; 117 | margin-bottom = 0pt; 118 | context-body = id; 119 | |) 120 | 121 | let new-description ?:min-indent itf it ctx idxlst = 122 | let min-indent = min-indent |> Option.from (get-font-size ctx *' 2.0) in 123 | let indent wid = 124 | Length.max min-indent (wid +' get-font-size ctx *' 1.0) 125 | in 126 | (| 127 | indent = (fun _ -> min-indent); 128 | indent-right = 0pt; 129 | label = read-inline ctx (itf it); 130 | label-with-empty-body = LabelDisplay; 131 | margin-top = 0pt; 132 | margin-bottom = 0pt; 133 | context-body = id; 134 | |) 135 | 136 | % setter 137 | 138 | let set-indent indentf fmt ctx idxlst = 139 | (| 140 | (fmt ctx idxlst) with 141 | indent = (indentf ctx); 142 | indent-right = 0pt; 143 | |) 144 | 145 | let set-context-body ctxf fmt ctx idxlst = (| (fmt ctx idxlst) with context-body = (fun ctx -> ctxf ctx idxlst); |) 146 | 147 | let set-label-display fmt ctx idxlst = (| (fmt ctx idxlst) with label-with-empty-body = LabelDisplay; |) 148 | let set-label-inherit fmt ctx idxlst = (| (fmt ctx idxlst) with label-with-empty-body = LabelInherit; |) 149 | let set-label-ignore fmt ctx idxlst = (| (fmt ctx idxlst) with label-with-empty-body = LabelIgnore; |) 150 | 151 | end 152 | -------------------------------------------------------------------------------- /src/param.satyh: -------------------------------------------------------------------------------- 1 | @require: base/ref 2 | 3 | module EnumitemParam : sig 4 | 5 | % 3 つの要素の直積. 6 | % - デフォルト値 7 | % - ユーザが定義した値(無いこともあるので 'a option) 8 | % - mutable かどうかを表す bool. 9 | type 'a t 10 | 11 | % デフォルト値を指定して make 12 | val make: 'a -> 'a t 13 | 14 | % 要素/情報の取得. 15 | val get : 'a t -> 'a 16 | val get-default: 'a t -> 'a 17 | val get-custom: 'a t -> 'a option 18 | val is-mutable: 'a t -> bool 19 | val has-changed: 'a t -> bool 20 | 21 | val set : 'a -> 'a t -> unit 22 | val fix: 'a t -> unit 23 | val unfix: 'a t -> unit 24 | val discard : 'a t -> unit 25 | 26 | direct +set-param : ['a t; 'a] block-cmd 27 | direct \set-param : ['a t; 'a] inline-cmd 28 | 29 | direct +with-param : ['a t; 'a; block-text] block-cmd 30 | direct \with-param : ['a t; 'a; inline-text] inline-cmd 31 | 32 | end = struct 33 | 34 | type 'a t = 'a * (('a option) ref) * (bool ref) 35 | 36 | let make value = (value, Ref.make None, Ref.make true) 37 | 38 | let get-default param = 39 | let (default, custom-opt, mutable) = param in 40 | default 41 | 42 | let get-custom param = 43 | let (default, custom-opt, mutable) = param in 44 | Ref.get custom-opt 45 | 46 | let is-mutable param = 47 | let (default, custom-opt, mutable) = param in 48 | Ref.get mutable 49 | 50 | let get param = 51 | let (default, custom-opt, mutable) = param in 52 | match Ref.get custom-opt with 53 | | Some(custom) -> custom 54 | | None -> default 55 | 56 | let has-changed param = 57 | let (default, custom-opt, mutable) = param in 58 | match Ref.get custom-opt with 59 | | Some(custom) -> true 60 | | None -> false 61 | 62 | let set value param = 63 | let (default, custom-opt, mutable) = param in 64 | if Ref.get mutable then 65 | custom-opt |> Ref.set (Some(value)) 66 | else 67 | display-message `[WARN] Failed to change a parameter (immutable).` 68 | 69 | let fix param = 70 | let (default, custom-opt, mutable) = param in 71 | mutable |> Ref.set false 72 | 73 | let unfix param = 74 | let (default, custom-opt, mutable) = param in 75 | mutable |> Ref.set true 76 | 77 | let discard param = 78 | let (default, custom-opt, mutable) = param in 79 | if Ref.get mutable then 80 | custom-opt |> Ref.set None 81 | else 82 | display-message `[WARN] Failed to change a parameter (immutable).` 83 | 84 | let-block ctx +set-param param value = 85 | let () = set value param in 86 | block-nil 87 | 88 | let-inline ctx \set-param param value = 89 | let () = set value param in 90 | inline-nil 91 | 92 | let-block ctx +with-param param value bt = 93 | let old-value = get param in 94 | let () = set value param in 95 | let bb = read-block ctx bt in 96 | let () = set old-value param in 97 | bb 98 | 99 | let-inline ctx \with-param param value it = 100 | let old-value = get param in 101 | let () = set value param in 102 | let ib = read-inline ctx it in 103 | let () = set old-value param in 104 | ib 105 | end 106 | 107 | --------------------------------------------------------------------------------