⛄️

今年作ったパッケージを振り返る

2020/12/24に公開

この記事は SATySFi advent calendar 2020 の24日目の記事です。
昨日は amutake さんによる記事「shinchoku-tairiku.satyh をリファクタしている話」でした。
明日(最終日!)は puripuri2100 さんによる記事「learn-satysfiの紹介」です。

こんにちは、monaqaです。もう年末も近いので、本記事では今年作った・更新したパッケージを振り返ります。

enumitem

https://github.com/monaqa/satysfi-enumitem

enumitem パッケージ自体は去年から存在していましたが、今年は Satyrographos にパッケージを登録し、さらにバージョンを v0.1.0 から v2.0.0 まで上げました。去年の SATySFi Advent Calendar 2019 にてパッケージの紹介記事を書いたものの、メジャーバージョン変更に伴い API が大きく変更されています。使い方は記事の方ではなくドキュメントを参照してください。

概要

様々なスタイルの箇条書きを提供するパッケージです。LaTeX の enumitem パッケージに相当するものが SATySFi でも欲しい、と思い作成しました。

enumitem パッケージのドキュメントからいくつか例を抜粋します。ここに挙げた機能が全てではありませんし、ドキュメントにはもっとたくさんの例も載っていますから、もっと詳しく知りたい方はそちらを参照してください。


ネストされた番号付き箇条書きの例

コード例
(markup)
+listing?:(Enumitem.(
  change-by-depth [ bracket-Alph; white-bullet; paren-arabic; ]
)){
  * hoge
  * fuga
    ** fuga1
      *** fuga11
      *** fuga12
    ** fuga2
}


TODO リストのように部分的にラベルを変える例

コード例
(preamble)
let square-label is-checked ctx =
  let fs value = (get-font-size ctx) *' value in
  let fsize = fs 1.0 in
  let gr-square (x, y) =
    stroke 0.5pt Color.black (Gr.rectangle (0pt, 0pt) (fs 0.5, fs 0.5 ))
      |> shift-graphics (x, y +' fs 0.15)
  in
  let gr-mark-done (x, y) =
    stroke 0.5pt Color.black (
      Gr.poly-line (fs (0.0 -. 0.1), fs 0.45) [(fs 0.15, fs 0.15); (fs 0.75, fs 0.85)])
        |> shift-graphics (x, y +' fs 0.15)
  in
  let gr point =
    if is-checked then
      [gr-square point; gr-mark-done point]
    else
      [gr-square point]
  in
  inline-skip 10pt ++ (inline-graphics fsize fsize 0pt gr)

let done = EnumitemBase.make-param false
let-inline \done = {\set-item(done)(true);}
let-block +todo-list item = '<%
  +xgenlisting(fun idx ctx -> square-label (EnumitemParam.get done) ctx)(default-item)(item);
>%
(markup)
+todo-list{
  * ミルクを買う.
  * The \SATySFi;book を読む.
  * \done; \SATySFi; を完全に理解する.
  * 課題を解く.
}


定義リストの例

コード例
(preamble)
let-block +parameters item = '<%
  +gendescription(|
    nextline = false;
    title-inner-gap = 10pt;
    inner-indent = (fun title-wid -> 30pt);
    title-func =
      (fun ctx title -> read-inline ctx {\emph{#title;}} );
  |)(item);
>%
(markup)
+parameters{
  * item-indent-ratio
    ** float 型のパラメータ (default: 2.0)
    ** 現在のフォントサイズに対する相対的な割合を指定して,
       箇条書きのネストが行われたときに,自分の親の項目から行うインデントの量を表す.

  * label-width-ratio
    ** float 型のパラメータ (default: 2.0)
    ** 現在のフォントサイズに対する相対的な割合を指定して,
       デフォルトで定義されている `raw-arabic` や `bullet` などのラベルの幅を表す.
       これらのラベルは右揃えで組まれるが,
       その際に必ず (`font-size *' label-width-ratio`) の分だけの空白が左端から確保される.
}

備考

私が作ったパッケージの第一号です(たぶん)。今年の abenori さんの記事でもご紹介いただきました。自分のパッケージを使ってくれる人がいるというのはとても嬉しいですね。ありがとうございます。

勢い余ってメジャーバージョン v2.0.0 にあげてしまいましたが、API はまだ模索中ですし、そもそも SATySFi 本体が破壊的変更を行った場合にはこちらのパッケージも様々な破壊的変更が起きる可能性が高いです。

SLyDIFi

https://github.com/monaqa/slydifi

SLyDIFi も去年から存在していましたが、2020年に Satyrographos に登録し、機能を色々追加しました。

概要

SATySFi でスライドを作成するためのパッケージです。

今年開かれた SATySFi Conf 2020 での私の発表に用いたスライド資料は SLyDIFi で作られています。その中からいくつかのスライドを例として抜粋します。

SLyDIFi にもドキュメントがありますから、詳細はそちらを参照してください。


基本的なスライドの例

コード例
(preamble)
let emphbox fb =
  let clr =
    SlydifiColor.inner-color SlydifiHakodate.cfg-color#title SlydifiHakodate.cfg-color#bg 0.1
  in
  fb |> glass-box 680pt 40pt |> bgcolor clr
(markup)
+frame{現在の\SATySFi;の表組版事情}<%
  +p{
    『The \SATySFi;book』 9.4節 表組版 (p. 117) より引用
  }
  +quote<
    +p{
      表組版は,全組版処理システムの泣き所である.
      簡潔なインターフェイスにすると機能が貧相になり,
      かといって高い自由度を保とうとすると簡素な表を組みたい場合でもかなり記述量が多くなってしまったりする.
      現状の \SATySFi; の表組版機能は,後者に振り切れたような形式化が行なわれている.
    }
  >

  +fig-center(
      textbox {デフォルトでは\uline{複雑な表が組めるが,面倒}}
        |> emphbox
  );
>%


画像の挿入の例

コード例
(markup)
+frame{まとめ}<%
  +fig-on-right(
    vconcat ?:align-center [
      textbox ?:(set-font-size 12pt) {リポジトリはこちら};
      gap 10pt;
      include-image 100pt `fig/jpg/qr-easytable-repo.jpg`;
    ] |> hvmargin 10pt |> frame 1pt Color.black
  )<%
    +listing{
      * \link?:({satysfi-easytable})(`https://github.com/monaqa/satysfi-easytable`);
        で楽に表が書ける
        ** 行揃え,行幅指定をサポート
        ** 罫線・背景色の指定も可能
        ** 関数をフルに活かした拡張性の高い API
    }
  >%
  +listing{
    * (宣伝)よければ以下も使ってみてください
      ** \textbf{\SLyDIFi;} (\link(`https://github.com/monaqa/slydifi`);)
      ** \textbf{satysfi-enumitem} (\link(`https://github.com/monaqa/satysfi-enumitem`);)
  }

  +fig-center(
    vconcat [
      gap 20pt;
      textbox {\textbf{Happy \SATySFi;ing!}}
        |> emphbox;
    ]
  );
>%



オーバーレイの例

コード例
(markup)
+multiframe(2){自己紹介}<%
  +fig-on-right(include-image 130pt `fig/pdf/logo-190727.pdf` |> frame 0.8pt (Color.black) )<%

    +listing{
      * 名前:monaqa
        ** Twitter: \link(`https://twitter.com/mo_naqa`);
        ** GitHub: \link(`https://github.com/monaqa`);
    }

  >%

  +listing{
    * 今までに作成した\SATySFi;のパッケージ

      \ctx(set-font-size 18pt){
        \text-color?:(only 2)(Color.gray 0.6){
          \description{
            * \textbf{\SLyDIFi;} (\link(`https://github.com/monaqa/slydifi`);)
              ** スライド作成のためのクラスファイル(このスライドも\SLyDIFi;製)
            * \textbf{satysfi-enumitem} (\link(`https://github.com/monaqa/satysfi-enumitem`);)
              ** 豊富なスタイルの箇条書きを簡単に組む
            * \emph?:(only 2){\textbf{satysfi-easytable}}
              \text-color(Color.black){(\link(`https://github.com/monaqa/satysfi-easytable`);)}
              ** \text-color(Color.black){シンプルな表を簡単に組む}
            * etc.
          }
        }
      }
  }
>%

全体のコードはまだ公開していないものの、スライド自体は Speaker Deck で公開しています(タイトルから分かるように、発表の趣旨は次に紹介する satysfi-easytable パッケージの紹介です)。

(embed するとなぜか両端が途切れてしまうため、ちゃんと見たい方はリンクを踏んでください)

備考

図表を整列して配置できる FigBox モジュール、 スライドを部分的に変えてアニメーションのように並べるオーバーレイ機能が個人的にはお気に入りです。
特に FigBox は SATySFi の関数型言語の強みを活かしたインターフェースとなっています。たとえば

hconcat [
  include-image 100pt `file1.pdf`;
  gap 20pt;
  include-image-with-height 150pt `file2.jpeg`;
] |> hvmargin 10pt |> frame 1pt Color.black

は「file1.pdf を横幅100ptで、 file2.jpeg を縦幅150ptで読み込み、20ptの間隔を空けて横に結合し、縦横に10ptの余白を付け、線幅1ptの黒い枠で囲む」という操作でできる図を表しています。

現在の SLyDIFi ではデフォルトテーマが3種類用意されており、さらにスライドテーマに相当するヘッダファイルを書き換えることでユーザがスライドテーマをいじれるようになっています。将来的には、今後実装されるかもしれないファンクタ機能 などを用いて、ユーザがよりテーマをいじりやすいモジュールにできないかと妄想しているところです。

easytable

https://github.com/monaqa/satysfi-easytable

概要

標準パッケージでは複雑なプログラミングを必要としていた表組版を、比較的単純なAPIを持つコマンドで実現するパッケージです。去年のはじめ頃に着想を得て実装しました。「とにかく簡単に表を組みたいんだ」という思いから easytable という名前にしています。そのまんまですね。

先程貼ったスライド資料を見た方は概ねどんな風に書けるか分かったかもしれませんが、easytable パッケージのドキュメント に置いた例も載せておきます。


単純な表の例

コード例
(markup)
\easytable[l;c;r]{
  | header1    | header2      | header3
  | align left | align center | align right
  | a          | b            | c
  |}


横幅を指定した表の例

コード例
(markup)
\easytable[l; lw 120pt; lw 120pt;]{
  | Column 1 | Column 2   | Column 3
  | 通常の列 | 横幅 120pt
  | 横幅 120pt で,なおかつ横幅よりも長いテキストが入っている場合
  |}


罫線を指定した表の例

コード例
(markup)
\easytable?:[t; b; m 2][r; c; l]{
  | How | I | want | a | drink | alcoholic | of | course
  | after | the | heavy | lectures | involving | quantum | mechanics
  |}
\easytable?:[t; b; m (-2)][r; c; l]{
  | How | I | want | a | drink | alcoholic | of | course
  | after | the | heavy | lectures | involving | quantum | mechanics
  |}


罫線と背景色を指定した表の例

コード例
(markup)
\easytable?:[bg-c Color.red 1 2][r; c; l]{
  | How | I | want | a | drink | alcoholic | of | course
  | after | the | heavy | lectures | involving | quantum | mechanics
  |}
\easytable?:[
  bg-a (Color.gray 0.8);
  bg-c (Color.red) 1 2;
  bg-r (Color.yellow) 1 3;
  t; b; v 1;
][r; c; l]{
  | How | I | want | a | drink | alcoholic | of | course
  | after | the | heavy | lectures | involving | quantum | mechanics
  |}


箇条書きの入力をもとに組んだ表の例

コード例
(markup)
\list-table[r; lw 140pt; lw 120pt;]{
  *
    ** 言語
    ** 代表的なパングラム
    ** 代表的な回文

  *
    ** 日本語
    ** いろはにほへとちりぬるを
       わかよたれそつねならむ
       うゐのおくやまけふこえて
       あさきゆめみしゑひもせす
    ** 長き夜の遠の睡りの皆目醒め波乗り船の音の良きかな

  *
    ** 英語
    ** The quick brown fox jumps over the lazy dog.
    ** Some men interpret nine memos.
}


高度な整列(padding調整、均等揃え)の例

コード例
(markup)
\easytable?:[t; b; m 1; v 2]
[r |> hmgn 10pt 0pt; l |> hmgn 0pt 10pt; eq-sp]{
  | 月/|日 | 2020 年 の 祝 日
  |  1/|1  | 元 日
  |  1/|13 | 成 人 の 日
  |  2/|11 | 建 国 記 念 の 日
  |    |   | (中略)
  |  9/|22 | 秋 分 の 日
  | 11/|3  | 文 化 の 日
  | 11/|23 | 勤 労 感 謝 の 日
  |}

備考

個人的に、easytableはAPIの設計という観点で最も気に入っているパッケージです。

  • (OCaml と文法が似ていることから)関数の部分適用を簡潔に表現できる
  • インラインテキストのリストに関する糖衣構文がある

といった SATySFi の文法を活かした設計にしました。

もっとも、今後 SATySFi の糖衣構文が新たに加わったりした場合(たとえばリストのリストが簡潔に書けるようになるなど)は設計を見直す可能性があります。

AZmath

https://github.com/monaqa/satysfi-azmath

概要

数式を組む際に役立つ様々なコマンドを提供するパッケージです。LaTeX でいうところの amsmath パッケージのように、SATySFi にとって事実上の標準となることを密かに狙っています[1]

AZmath パッケージのドキュメントからいくつか例を抜粋します。例によって、ここに挙げた機能が全てではありません。もっと詳しく知りたい方はドキュメントを参照してください。

数式環境

LaTeX でいう equation 環境や(amsmath パッケージの) align 環境などに相当するコマンドです。自動連番のタグ付け、ラベルを用いた相互参照などをサポートしており、LaTeX のものと同程度に手軽に使用できます。現在、特にイチ推しの機能です。


+gather コマンドの例

コード例
(markup)
+gather(${
  | \p{x + y}^2 = x^2 + 2xy + y^2,
  | \p{x + a}\p{x + b} = x^2 + \p{a + b} x + ab,
  | \p{x + y}\p{x - y} = x^2 - y^2.
  |});


+align コマンドの例

コード例
(markup)
+align(${
  | \p{x + y}\p{x - y} |= x^2 -xy + xy - y^2 \notag
  |                    |= x^2 - y^2.
  |});


\cases コマンドの例

コード例
(markup)
+eqn(${
  y = \cases{
  | x      | \p{x \geq 0}
  | \neg x | \p{x < 0}
  |}
  });


数式にタグを付け、相互参照する例

コード例
(markup)
+gather(${
  | \p{x + y}^2 = x^2 + 2xy + y^2,               \label!(`formula1`)
  | \p{x + a}\p{x + b} = x^2 + \p{a + b} x + ab, \label!(`formula2`)
  | \p{x + y}\p{x - y} = x^2 - y^2.              \label!(`formula3`)
  |});

+p{
  付与した数式は ``\ref(`eq:formula1`);`` とすることで参照することができます。
  たとえば先程の例の一番上の式は (\ref(`eq:formula1`);) 式でした。
}


数式に任意の名称のタグを付ける例

コード例
(markup)
+gather(${
  | \p{x + y}^2 = x^2 + 2xy + y^2,  \label?:!(`1-a`)!(`formula4`)
  | \p{x + y}\p{x - y} = x^2 - y^2.
    \label?:!(`very long tag`)!(`formula5`)
  |});


ラベルを指定した数式のみにタグを付ける例

コード例
(markup)
+gather?:(AZMathEquation.notag)(${
  | \p{x + y}^2 = x^2 + 2xy + y^2,
  | \p{x + a}\p{x + b} = x^2 + \p{a + b} x + ab,
  | \p{x + y}\p{x - y} = x^2 - y^2. \label!(`formula-notag`)
  |});


長い数式のときは自動でラベルが下にずれてくれるという例

コード例
(markup)
+gather(${
  | \p{a + b + c + d + e}\p{x + y}
    = ax + ay + bx + by + cx + cy + dx + dy + ex + ey
  | x^3 + y^3 + z^3 - 3xyz =
    \p{x + y + z}\p{x^2 + y^2 + z^2 - xy - yz - zx}
    \label?:!(`long tag`)!(`long-tag-formula`)
  |});
>%

アクセント

\hat\tilde などのアクセント記号です。


アクセントの例

コード例
(markup)
+gather(${
  | \tilde{a}, \tilde{b}, \tilde{c}, \tilde{d}, \tilde{e}, \tilde{f},
    \tilde{g}, \tilde{h}, \tilde{i}, \tilde{j}, \tilde{k}, \tilde{l}, \tilde{m},
    \tilde{n}, \tilde{o}, \tilde{p}, \tilde{q}, \tilde{r}, \tilde{s},
    \tilde{t}, \tilde{u}, \tilde{v}, \tilde{w}, \tilde{x}, \tilde{y}, \tilde{z},
  | \bar{a}, \bar{b}, \bar{c}, \bar{d}, \bar{e}, \bar{f},
    \bar{g}, \bar{h}, \bar{i}, \bar{j}, \bar{k}, \bar{l}, \bar{m},
    \bar{n}, \bar{o}, \bar{p}, \bar{q}, \bar{r}, \bar{s},
    \bar{t}, \bar{u}, \bar{v}, \bar{w}, \bar{x}, \bar{y}, \bar{z},
  | \adot{a}, \adot{b}, \adot{c}, \adot{d}, \adot{e}, \adot{f},
    \adot{g}, \adot{h}, \adot{i}, \adot{j}, \adot{k}, \adot{l}, \adot{m},
    \adot{n}, \adot{o}, \adot{p}, \adot{q}, \adot{r}, \adot{s},
    \adot{t}, \adot{u}, \adot{v}, \adot{w}, \adot{x}, \adot{y}, \adot{z},
  | \ddot{a}, \ddot{b}, \ddot{c}, \ddot{d}, \ddot{e}, \ddot{f},
    \ddot{g}, \ddot{h}, \ddot{i}, \ddot{j}, \ddot{k}, \ddot{l}, \ddot{m},
    \ddot{n}, \ddot{o}, \ddot{p}, \ddot{q}, \ddot{r}, \ddot{s},
    \ddot{t}, \ddot{u}, \ddot{v}, \ddot{w}, \ddot{x}, \ddot{y}, \ddot{z}.
  | \breve{a}, \breve{b}, \breve{c}, \breve{d}, \breve{e}, \breve{f},
    \breve{g}, \breve{h}, \breve{i}, \breve{j}, \breve{k}, \breve{l}, \breve{m},
    \breve{n}, \breve{o}, \breve{p}, \breve{q}, \breve{r}, \breve{s},
    \breve{t}, \breve{u}, \breve{v}, \breve{w}, \breve{x}, \breve{y}, \breve{z}.
  |});

括弧


括弧の例

コード例
(markup)
+gather(${
  | \pb{\frac{1}{2} \pb{\pb{\pb{x + 1} + x}^2}}
  | \pB{\frac{1}{2} \pB{\pB{\pB{x + 1} + x}^2}}
  | \pabs{\frac{1}{2} \pabs{\pabs{\pabs{x + 1} + x}^2}}
  | \pnorm{\frac{1}{2} \pnorm{\pnorm{\pnorm{x + 1} + x}^2}}
  | \pangle{\frac{1}{2} \pangle{\pangle{\pangle{x + 1} + x}^2}}^2
  |});


\underbrace コマンドの例

コード例
(markup)
+gather(${
  | x = \underbrace{
      \overbrace{ a + \underbrace{b + c}_{=0} }^{\text!{foo}}
      + d + \overbrace{e + f}
    }_{=0}
  |});

行列


行列の例

コード例
(markup)
+gather(${
  | A = \pmatrix!(2){| a | b | c | d |}
  | A^{-1} = \frac{1}{ad - bc} \pmatrix!(2){|d|\neg b|\neg c|a|}
    = \pmatrix!(2){
    |      \frac{d}{ad - bc} | \neg \frac{b}{ad - bc}
    | \neg \frac{c}{ad - bc} |      \frac{a}{ad - bc}
    |}
  |});

備考

最初は SATySFi の標準の数式パッケージに足りない機能を補うことを主眼としていたものの、コマンド名の衝突などがちょっと気になるので、そのうち標準の math パッケージにあるものを全て実装し尽くして、標準の math をインポートしなくても azmath を入れるだけで完結するようにするかもしれません。

おわりに

どのパッケージもユーザ数はまだまだ決して多くありませんが、 16日目の abenori さんの記事 で紹介していただいたように、自分のパッケージを使ってくださっている人をちらほらお見かけできたのは嬉しかったです。Satyrographos で簡単にインストールできるようにする効果はやはり大きそうですね。
今のところは自分が SATySFi で文書を組んでいるうちに欲しくなった機能を中心に追加しているにすぎませんが、自分以外の人にも便利だなと思ってもらえるようどんどん発展させたいとは思っています。「こんな機能がほしい」というアイデアがあれば、是非 Issue ないし PR を送っていただけるとありがたいです。

脚注
  1. ここに書いた時点で「密か」ではなくなってしまいましたが。 ↩︎

Discussion