SATySFiで作った冊子のお話

SATySFi Advent Calendar 2021の最終日の記事です。

24日目の記事はmonaqaさんによる「satysfi-enumitem v3.0 で素敵な箇条書きをいっぱい作る話」でした。

はじめに

SATySFiは最近登場した、テキストファイルをもとにPDFを作成する組版ソフトウェアです。独自の文法をもつマークアップ言語でもあります。また、組版処理を自動化したり、制御したりするための「組版プログラミング言語」の面も持ちます。この部分は静的型付けの関数型言語という言語設計上の特性があります。

ここ数年でSATySFi関連の素晴らしいツールやパッケージが数多くリリースされ、SATySFiで文書を作る環境は整ってきています。

しかし、SATySFiで作られた文書についての情報がまだあまりないので、それについて今回簡単に紹介してみようと思います(yabaitech.tokyoさんや進捗大陸さんがSATySFiで同人誌を作成していることは有名で、ノウハウも記事として出てますが、それの足しになれば幸いです)。

これを参考に「SATySFiって色々使えるんだな」とか「SATySFiで冊子を作るときにこういうことを考えているんだな」とか思ってくださるとうれしいです。

自分がSATySFiで作成し、今回紹介する冊子は - 高校の文化祭で配布する部誌 - 毎年、高三のときに高校のクラスごとに作成するプチ卒業アルバムのような200ページの冊子(運動会活動に絡めて作成されるため、「運動会パンフレット」と呼ばれています) - 高校の卒業文集 の3つになります。

本当はすべて公開して詳しく書いていきたいところですが、個人情報の塊のものが多いのであまり詳しく説明できず簡単な紹介になってしまいす。

では、順番に紹介していきます。

部誌

中高のときにパズル研究部というところに所属しており、そこでは編集長として部誌を作成し配布していました。SATySFiで作成した年には部誌としてはかなり長大となる120ページのものとなりました。これを1000部以上刷って製本して配布しました(学校の輪転機で数十時間使って刷り、部員総出で一枚ずつ集めて冊子としてステープラーで止めていました)。下手なサークルより作ってますね。しかもほぼ全部捌けるんです。

レイアウトの制約については3年前に同じく編集長として部誌をLuaLaTeXで作った時に書いたブログ(LuaLaTeXで部誌を作った話)を読んでいただきたいのですが、簡単にいうと

  • 「問題番号」・「作者名」・「問題の難易度」・「パズルの画像」の4つの要素からブロックを作成し、それを紙面上に並べていく
  • 問題番号に対応する解答画像も別のページに並べる

といった感じになっています。

  • 作者名
  • 難易度
  • 画像のファイル名

のタプルのリストを作成し、そのリストを処理してページを生成する関数を作って自動組版していきました。

また、記事部分もあるので、そこは普通に標準クラスのような感じのレイアウトになるようにコマンドを提供し、それで組んでいきました。

特徴的な機能としては、SATySFiのテキスト出力モードを利用し、PDFと同時にHTMLを吐き出すようにした点があるかもしれません。

パズル研究部のHPの部誌掲載のページの「2019年(ニポリ16号)」をご覧ください。「PDF版」と「HTML版」の二つがあることがわかると思います。これは両方とも同じソースから生成しています。

後悔しているのは、吐き出すHTMLファイルに"id"による参照機能をつけ忘れたことです。どうにかしたいですね。

(製本した部誌はしまってしまったので今写真がありません)

運動会パンフレット

例年Adobe InDesignを使用して作成されているのですが、よい機会なのでSATySFiで作ってみました。

クラスの人について一人一人紹介するページが2ページずつ50人分あり、ここを自動化できればかなり労力の削減につながるということで自動化しました。

出席番号ごとに紹介文を"1.satyg"や"50.satyg"というようファイル名をつけ、中で

let a-1 = '<
  +p{紹介文}
>

というようにblock-textとして保存をし、それを出席番号ごとに呼び出していく感じにしました。これでメインファイルでは

+syoukai <
  +s (1) (a-1);
  +s (2) (a-2);
  +s (3) (a-3);
  +s (4) (a-4);
  ...
  +s (50) (a-50);
>

と書くだけでよくなります。また、こうすることで特定の一人の文章を変更するときに変更差分がわかりやすくなります(Gitを使ってバージョン管理をしていたので)。

もちろん、出席番号から名前と顔写真を引っ張ってきて、文章と共に適切に組んでいくコマンドを関数を作ることが必要ですが、そこはSATySFiの「組版プログラミング言語」としての面を活用すれば十分に行えます。そしてなにより、デザインを変更する際に一発で反映させられるという素晴らしい利点があります。

この冊子でも部誌と同じように記事部分があるので、そこも部誌と同じように適当に良い感じにしました。

紹介部分は画像のようになっています。かなりシンプルなデザインとなってはいますが、それっぽくはなっているのではないでしょうか(右側のぼかされているところが個人紹介の文章となっています)。

f:id:puripuri2100:20211231180740p:plain
パンフの個人紹介のページ

シンプルなデザインになった言い訳をすると、コロナ禍によるオンライン授業の影響で自分が編集担当になったのが遅く、長期休みまでに紹介文の回収をしようとすると、早くレイアウトを決定しなければならなくなったためです。適当な字数を制約として紹介文を書かせて、後からレイアウトを決めていけばもっと凝れたのでしょうが、もし改行数を多くして送って来られたりするとかなり面倒なことになってしまうので「一行○○文字で△△行まで」として書かせたかったのです。SATySFiのグラフィック機能を使って飾りつけをすることも一瞬考えましたが、「無償でやってるんだからそこまでしなくて良いだろう」ということでやめました。

ところで、氏名を表示するところが縦組みっぽい何かになっていますね。この運動会パンフレットを作ったときはv0.0.6のときなので縦組み機能はありません。頑張って一文字ずつdraw-textプリミティブを使って縦組みっぽく配置しています。

卒業文集

今絶賛印刷製本中になるわけですが、高校卒業文集もSATySFiで作っています。

部誌も運動会パンフレットもすべてSATySFiで作成しましたが、この卒業文集は「生徒の書いた文章部分はSATySFiで作る」「扉や表紙などは別のGUIソフトで作成する」と役割分担をしました。

卒業文集も運動会パンフレットと同じように、同じレイアウトで数百人分のページを作るものなので、SATySFiでプログラムを組んで自動化することのメリットがかなり出たのではないかと思います。逆に、各ページごとの調整がかなり細かく必要となった組ごとの扉ページについてはそれが得意なソフトウェアを活用しています。

これも運動会パンフレットと同じく、一人一人ファイルを作成して読み込んでいます。ただ、メインファイルで全員分を一気に読み込むとプリアンブルだけで数百行になってしまうので、一旦クラスごとにまとめて class-1 のようなblock-textを作り、それを組の数だけメインファイルに書き込んでいます。階層化は大事ですね。

卒業文集委員会の委員長が、文章の提出方法を以下のような様式に指定して学年に通達してくれました。

  • 提出はメール本文に平打ちとし、docxファイルでの提出などは認めない
  • 本文の一行目には4桁番号のみを書くこと(「4桁番号」とは、学年・組・出席番号を順に並べたもので、例えば1年2組34番であれば「1234」となります)
  • 2行目には氏名のみを書くこと
  • 3行目にはタイトルのみを書くこと
  • 4行目以降は本文を書くこと ただし、全ての改行は改段落として扱う

かなり機械的に処理しやすい形式にしてくれました(もちろん、意図的に上の形式を課しています)。ですので、この形式に従ったテキストを処理して、自動で一人一人の文章をblock-textとして定義するsatygファイルを生成するプログラムを作って運用しました。

スクリプト言語で書くか、と思ったのでRubyで書いてみました。余計な改行などは手動で削除してそれをそのプログラムに投げれば終わりです。 後は4桁番号から組と番号を特定して自動でファイル作成をして本文を改行ごとに段落として+pコマンドに入れていきます。また、特殊文字などもエスケープするようにしています。

かなり便利で、単純なコピペを繰り返すだけで一人あたり一分でページが作られていきます(あれ?なんか遅いような気もするが?)。

「二段組のデザインにしたい」と委員長から要望されたので、SATySFiの二段組機能を用いて作成しました。

個人情報の塊かつ作成中のものなので残念ながら写真は出せません……。

使って便利だったパッケージ

satysfi-tombo

印刷所に入稿するPDFなので当然裁ち落としが必要になります。

そいうわけで、特に大きく手を加えることなく裁ち落としとトンボを自動でつけられるsatysfi-tomboパッケージがかなり便利でした。

使い方については「SATySFiでトンボと裁ち落としを設定するパッケージを作った話」という記事を読んでください。

satysfi-base

ベージ番号に関するフックをかなり活用しており、そのときにsatysfi-auxに書き出したページ番号を読み取ってint型に変換する必要がありました。そんなときにはint.satygに定義されている Int.from-string 関数がかなり便利でした。

satysfi-image

画像を回転させたりする必要があるときに便利でした。本当は無精せずにきちんと画像編集ソフトウェアで回転させてあげれば良いのでしょうが、さすがに数百枚もそんな編集はしたくなかったので……。

satysfi-easytable

「これは表です!」という感じで使うことはありませんでしたが、「よく考えたらこれは表だよな」という場合がいくつかあり、罫線の出し方を簡単に弄りつつさっさと作ることができて便利でした。

欲しいと思ったパッケージ

satysfi-auxファイルとのやりとりを上手くラップしてくれるパッケージが欲しいですね。一々プリミティブを使ったり、ラップする関数を定義していくのは面倒でした。

また、飾りなどを描画するときのデバッグ用としてheader・footer・本文箇所のそれぞれにグリッドを表示できるようなものとかも欲しいですね。

(こういうことを書いておくとpuripuri2100という人がやる気を出したときに作ってくれることがあるらしいです)

おわりに

今までSATySFiで作った冊子について簡単に紹介していきました。

公開しにくいものばかりなので写真などをほとんど出せないのが残念ですが、わりと重要な冊子の作成にSATySFiが結構使われていることがわかっていただけましたでしょうか?

自分はほかにも筑波大学AC入試の自己推薦を作成するときにもSATySFiを使ったりしました(クラスファイルのリポジトリ)。

SATySFiはきちんと実用されまくっている組版ソフトウェアです! 皆さんもぜひ使って楽しいSATySFiライフを送りましょう!

SATySFiで大学に受かった話(筑波大学AC入試合格体験記)

はじめに

先日、筑波大学情報学群情報科学類のAC入試で合格しました。 後は筑波大学が入学許可を正式にしてくださるかどうかにかかっていますが、無事に許可された場合、筑波大学情報学群情報科学類(以下、coinsと書くことにします)に学部一年生として入学することになります。

ここでは、「coinsのAC入試に受かるまでにしたこと」を記事にしたいと思います。平たく言えば「筑波大学情報学群情報科学類AC入試の合格体験記」というやつです。

志望校選び

「なぜ筑波大学情報学群情報科学類をAC入試で受ける選択をしたのか」ということについて簡単に説明したいと思います。

なぜ情報科学なのか

中学三年生のときに、SATySFiの実装について知りたくなった自分は「まずはラムダ計算ってやつについて知りたい」と思いました。そこで、学校の数学教師(「修士(情報)」持ち)と一緒に「型システム入門 プログラミング言語と型の理論(TaPL)」を読んでラムダ計算について勉強しました。 そこで自分は「自分は専門書を読んで理解しようとしても簡単に間違えるほどの能力しかないのだ。専門家の指導の下できちんと勉強しないと正しく知識を入れられない。」ということに気が付きます。

そしてプログラミングを趣味で続けていくうちに、いつしか「今のままの知識ではできることは限られる。大学で体型的に情報科学に触れて基礎をしっかりつけてできることを増やしたい。」と思うようになってきました。

というわけで、「できることを増やすために専門家のもとで情報科学を学ぶ」という目標ができ、「情報科学科志望の高校生」となるわけです。

なぜAC入試なのか

AC入試とは「アドミッションセンター入試」の略で、世間一般でいうところの「AO入試自己推薦入試・総合型選抜」と同じようなくくりです。 出身高校などからの推薦は不要ですが、テストの点数のみでは合否は決まらず、書類選考と面接が課せられることが大きな特徴です。

自分はもともと冬に精神状態が不安定になりやすく、とうとう高校二年生の冬に重度の抑うつ状態になってしまい、○○未遂に至るまでになってしまいます。精神科に通いながらも寛解まで半年もかかり、とてもしんどい思いをし続けました。 また、自分は勉強ができるわけではなく、一般入試でも非常に苦労することが容易に予想されました。

以上のことから、一般入試を受けることにすると、途中から

  • 合格に必要な学力に到達できず、劣等感が強く刺激される
  • 「合格できないかもしれない」という不安感を強く感じるようになる
  • 受験勉強そのものが強いストレスとなる

ということがおき、11月ごろから抑うつ状態に再度なることが予想されました。このような直前期に抑うつ状態になった場合、十中八九受験に失敗し浪人することになると思われます(「受験会場に行けない」になると志望校をどう変えようが落ちますからね)。浪人するとさらにストレスがかかり、寛解はほど遠くなり、悪循環に陥るでしょう。そのため、なんとしてでも「一般入試を回避しつつ現役合格をする」ということが必要になります。 さらに、受験期間と冬が被る時期を減らすために、合格がわかる日が早ければ早いほど良いことになります。

そこで当然目を付けるのが「推薦入試」です。

なぜ筑波大学なのか

推薦入試があって情報科学を学べ、できるなら文化系の授業も取れる大学を探すと、意外と数が絞られることがわかりました。その結果、候補として挙がったのは以下の大学と受験方式でした。ここら辺を調べたのは主に高校一年生の冬から高校二年生の夏にかけてでした。

京大特色は「面接で英語を使うらしい・めっちゃ難しそう」ということで早々に候補から消え、東工大もかなり迷っていたのですが、「単科大学である・筑波ACの合格発表後に出願できる」ことから保留になります。

東大推薦と筑波ACと筑波推薦の3つの中から選ぶことになるのですが、

  • 勉強できる環境
  • 自分ができること
  • 大学でやりたいこと
  • 情報科学科にある研究室の研究テーマ
  • カリキュラムの特性
  • 合格発表時期
  • 合格するための道筋

などから勘案して筑波AC入試をすることにしました。ここでかなり迷いました。本当は筑波ACと筑波推薦は両方出願できるのですが、「筑波推薦では受からんだろう・筑波推薦を取るための学内選抜の準備をするくらいなら筑波ACの準備をした方が良い」ということで諦めた感じです。

そういうわけで、高校三年生の6月頃には「筑波大学情報学群情報科学類をAC入試で受験する」ということを決めていました。

出願の準備

調査書発行や自己推薦書の添削、面接練習などで結局学年の先生に伝えることや、今まで進路の話を色々としていたことから、クラス担任の先生にcoinsをAC入試で受けることを伝えました。すると、ちょうど自分が6年間化学を教わっていた学年の化学教師がそういった推薦入試対策をしていた経験があることを教えていただいたので、その化学教師に相談することにしました。

志願理由書

執筆

相談の結果、志願理由書を書くことになり、6月から7月中旬にかけて志願理由書を書いては添削してもらっていました。一番参考にしたのは何と言ってもアドミッションポリシーです。coinsのアドミッションポリシーが

情報科学や情報技術,または関連する分野に強い関心を持ち,自ら研究課題と明確な目標を設定して問題の分析や解決を創造的に図る意欲と能力を有し,その過程と結果を論理的に説明することのできる人材を選抜します。

「令和4年度(2022年度)アドミッションセンター入試学生募集要項」より

となっていたので、

  • 情報科学の基礎を固め、OSSなどの形で貢献したい
  • やってみたい研究テーマ

などと絡めて書きました。

最初は字数オーバーで書き、そのあと少しずつ削っていく感じでした。

清書

要項によると、指定された用紙の上に文字が載っていないといけないらしいですが、どうしても原稿用紙用に文字数を調節することが面倒で、字を綺麗に沢山書きたくなかったので、自動化しました(パソコン使用可でした)。

具体的には、SATySFiで一文字ずつ原稿用紙の格子の中に収まるように行と列を計算して配置していくプログラムを書きました。

役物の処理が雑なのであまり本格的には使いたくないですが、文字数カウントの手間が省けたのでかなり楽でした。

自己推薦書

わりとメインの提出書類でした。

これもアドミッションポリシーに沿った内容を意識して「課題発見解決能力」を示せるエピソードになるようにしながら書きました。そしてこれも同じく沢山添削を受けました。

内容的には

  • OSS活動
    • ソフトウェア
    • イベント
  • 学校活動

みたいな感じでした。

図にすると

f:id:puripuri2100:20211214204339p:plain
自己推薦書の見取り図
みたいな感じになります(ちなみにこの図は自己推薦書の最初の方に載せました)。

作成したソフトウェアについてもっと書きたかったのですが、わりと内容が似た感じになりそうだったので、特徴的なものを選んで載せました。

ページ数は80ページほどになりましたが、これの多さはほとんど関係ない気がします。

補足資料としてソフトウェアのソースコードUSBメモリに入れて送りました。見てくれたのかは謎です。

自己推薦書を書く時には、技術記事やドキュメントを書いていた経験がかなり生きました。

その他

入学志願票・写真票などは印刷してそのまま入れました。

調査書はクラス担任の先生に伝えていたこともあってスムーズに発行できました。

長期休みとの兼ね合いもあるので、早めに手に入れるに越したことはないと思います。

ギリギリまで粘らず、事前に準備をすべて終え、9月1日に郵送しました。 書類がきちんと受理されたかどうかがわかるまで少しドキドキしました。

ところで、「期間内必着」ではなく「期間内消印有効」にして欲しいですね。早く着いた場合にどうなるのかわからないのが怖いです。

一次選考結果発表

10/1が合格発表でした。都民の日で学校が休みだったので、10時に確認することができました。

数日前からかなり緊張していました。最終合格発表よりも緊張したと思います。

coins22のAC入試ではここが3倍強の倍率だったようです。

教師と親から「不合格になるかもしれないから、出願後は勉強しようね」と言われていましたが、結局勉強せずにソフトウェア作っていました。現実逃避ってやつです。

面接対策

面接は一時合格発表の2週間ほど後の10/13にありました。

ここで落ちるわけにはいかないので対策をしっかりとやりました。手法としては「面接練習をしてフィードバックを貰い、それを基にして修正を加えていく」という感じにしました。

回答の主軸も当然アドミッションポリシーです。

面接練習は学校の先生と先輩に頼みました。本当にありがとうございました。

属性としては

  • クラス担任の数学教師
  • 学年の数学教師
  • 学年の化学教師
  • coins13ACで現在も筑波博士課程在学中の先輩
  • AO入試東北大学医学部に合格した3つ上の先輩

でした。

練習の中身としては主に

  • 「研究で社会にどう貢献するのか」というテーマ関連の質問
  • 「自分のやってきたこと・やりたい研究テーマ」に技術的な観点から踏み込んだ質問
  • 受験時のマナーと「自己推薦書の中身を纏めて短く説明する」ことの練習

をやっていただきました。それぞれかなり役に立ちました。

面接練習で貰ったアドバイスとしては

  • 先行研究についてもう一度まとめておく
  • 自己推薦書や志願理由書の中に説明が不十分な記述があるので、事前知識も踏まえて説明できるようにしておくこと
  • 自己アピールの機会があるかもしれないので、その時にいうことを決めておけ
  • 「大変だったこと」・「そのソフトウェアを作ったきっかけ」については話せるようにしておきたい
  • 研究テーマについては具体的に話せるようになっておいた方が良い
  • 情報科学の知識を対策のために新たに入れる必要はない
  • 回答で脇道にそれる必要はない
  • それぞれの成果で自分がやった範囲を明確にして説明する
  • 最初早口になるのはしょうがない
  • 受験番号をいう時などに声をきちんと出すことでリラックスできるようにしたい
  • 楽しめ

などでした。

数をこなすのはわりと重要だと思いました。

面接

遅刻をしないように2時間前に着くように行動した結果、事故無く着いたは良いものの、建物の中に入れずに凍えていました(雨が降っていました)。

面接自体は順調に終わりましたが、最後に受験票を忘れて退室するというへまをしました。

最終合格者発表

11/2に発表がありました。前日に学校の創立150周年記念式典があり、その代休で休みだったので、これも10時ちょうどに見ることができました。

嬉しかったです。

SATySFi的なお話

「SATySFiのおかげで大学に受かった話」ということで書いているので、最後にSATySFi要素に触れたいと思います。

技術面

志願理由書の自動生成

前述したように志願理由書の作成にSATySFiを用いました。

志願理由書の記入欄が原稿用紙のような格子状に区切りが入っていたため、

  1. 入力をstring-explode等を用いて一文字ずつに分割する
  2. マスの横幅と縦幅の値をもとにそれぞれの文字が配置される座標を計算する
  3. 計算結果の座標を基にdraw-textで描画する
  4. 背景にこれまたload-pdf-imagedraw-textで志願理由書のテンプレート用紙を配置する

という形で実装しました。

自己推薦書でのページ番号の処理

自己推薦書もSATySFiで作成しました。クラスファイルは一から作成しました。

そのクラスファイルとデモファイルを puripuri2100/tukuba-AC-cls というリポジトリで公開しました。

文書は

  1. はじめに
  2. 目次
  3. 本文
  4. おわりに
  5. 参考文献

によって構成され、「はじめに」と「目次」のページ番号はローマ数字にし、本文以降はアラビア数字でページ番号を表し、目次と本文の間でページ番号のカウンタをリセットするという形になっています。よくある本と同じ感じです。

これの実現方法ですが、

  1. hook-page-break-blockプリミティブとregister-cross-referenceプリミティブを用いて目次の終わりのページ番号を記録
  2. 二度目の処理でget-cross-referenceライブラリで目次の終わりのページ番号を取得し、baseライブラリの中のintパッケージで提供されているof-string関数を使ってint型にする
  3. ページ番号の計算を行った結果のページ番号を組むが、その際にローマ数字を出力するページでは、ローマ数字への変換にnum-conversionパッケージで提供されるto-roman-lower関数を使う

という感じでした。

自己推薦書での参考文献

参考文献はgfngfn/cs-thesisnamachan10777/BiByFiなどを参考にして自分でパッケージを作成して作りました。

SATySFiでの参考文献の作成についてはもっとアップグレードさせていける気がしました。

自己推薦書で使ったその他の技術

ルビを振る必要があったため、puripuri2100/satysfi-rubyを使ってルビを振りました。

画像貼り付けにはpuripuri2100/satysfi-imageを用いました。デフォルトで横幅がtext-widthになるようになっているのであまり考えなくてよかったです。クラスファイルの方で+figureコマンドを実装して使っていました。

我ながら便利なパッケージを作ったと、過去の自分に感謝しています。

書類内容面

自己推薦書に書いた内容の多くにSATySFiが絡みました。 書いているときにふと「自分の青春のほとんどはSATySFiだったのではなかろうか」と思うこともありました。

  • SATySFiのライブラリ作成について
  • SATySFi関連の便利ツール実装について
  • SATySFi本体への貢献について
  • SATySFi Conf主催について
  • SATySFiで部誌・運動会パンフレットを作成したことについて

など沢山書きました。これからもSATySFiに関わりながら楽しく活動していきたいと思います。

おわりに

今、生きるのに辛くて大学受験をどうすればいいのかがわからない高校生は筑波大学AC入試を選択肢の一つに入れてみてはどうでしょうか?

「表彰されたもの」・「世間的に評価された実績」・「良い成績」が全て無くとも合格することはできると思います。重要なのは「社会的ステータスがある活動のアピール」ではなく、「今までやってきた活動を踏まえて、自分がアドミッションポリシーに沿った人物であると売り込むこと」だけです。

応援しています。

最後に、今回の受験でお世話になった方々に感謝したいと思います。

ありがとうございました。

SATySFiでシンタックスハイライトが効くコード貼り付けパッケージ(code-printer)の紹介

はじめに

今年も始まりましたSATySFi Advent Calendar 2021

今年もSATySFi関係の記事を充実させていきましょう。

そろそろSATySFi v0.1.0のリリースがあるということで、これからも楽しみですね。

さて、今回はSATySFiでソースコードを表示するためのcode-printerというパッケージを作成したので、これについて記事を書いていきたいと思います。

パッケージのリポジトリは"puripuri2100/satysfi-code-printer"にあり、satyrographos-package-indexでのページは"packages/code-printer"にあります。

最新版のマニュアルはpuripuri2100.github.io/satysfi-code-printer/code-printer-ja.pdfにあります。

記事執筆時点でv1.0.0です。 v2.0.0以降のバージョンはおそらく挙動が変わっているでしょうから、この記事はあまり役に立たないでしょう。

このパッケージの強み

このパッケージはLaTeXでいうところのlistingsパッケージと似たような機能を持ち、さらにSATySFiならではの独自の強みも持っています。すなわち、

  • 言語によるシンタックスハイライトを提供する
  • フォント・フォントカラー・背景色などのテーマを変更できる
  • コード枠や行番号などの装飾を変更することができる
  • 高速に動作する
  • マルチバイト文字列もある程度対応している(結合する文字への対応は不可能)
  • 40程度のシンタックスハイライトと20強のテーマをデフォルトで提供している
  • ユーザーが独自にシンタックスハイライトやテーマを作成することが可能

という特徴があります。

インストール

SATySFiのパケージマネージャであるSatyrographosを用いてインストールすることを想定しています。

v0.0.6リリース後に追加されたread-fileという外部ファイル読み込みプリミティブを使用しているため、v0.0.6-53-g2867e4d9以降のSATySFiでなければなりません。

opam update

opam install satysfi-code-printer

satyrographos install

と、それぞれ実行することでインストールされるはずです。

もしSATySFiをリポジトリから直接ビルドして使っていてタグがv0.0.6のままの人は、

opam pin add "git+https://github.com/puripuri2100/satysfi-code-printer.git"

opam install satysfi-code-printer

satyrographos install

をしてcode-printerのリポジトリから直接インストールしてください(リポジトリのHEADではv0.0.6のままでインストールができるようなバージョン制約がopamファイルに書いてあるからです。)

もしSATySFi v0.0.7がリリースされ、それを使うことになった場合は

opam pin remove satysfi-code-printer

opam update

opam install satysfi-code-printer

として、satyrographos-repoの制約のほうを使うことを推奨します。

超簡単な使い方

プリアンブルに

@require: code-printer/code-printer

と書くことで提供されるコマンドを使用することができます。 モジュール名はCodePrinterです。

提供するコマンドは

  • \inline-code
  • +code-printer
  • \code-printer
  • +file-printer
  • \file-printer

の5つです。

これらの5つのコマンドの型は全て

[code-printer-config?; string]

となっています。

オプション引数で設定を渡し(渡さないこともでき)、コードを与えることで組版されます。+file-printer\file-printerについては、コードではなく貼り付けたいファイルのパスを与えます。

シンタックスハイライトをつけたり、カラーテーマを変更したり、デザインを変更したりすには、オプション引数で設定を与える必要があります。

言語・テーマの設定の仕方

+code-printer ?:(
  CodePrinter.make-config syntax theme
) (`code`);

のようにして言語とカラーテーマを選択することができます。

言語はデフォルトでいくつか用意されており、

@require: code-printer/code-syntax

で読み込んだパッケージ(提供モジュール名はCodeSyntax)で40個弱提供されています。詳細はドキュメントやREADMEを見ていただくとして、一例を挙げるとこのようになっています。

f:id:puripuri2100:20211201200945p:plain
プログラミング言語のsyntaxの例

カラーテーマはデフォルトでいくつか用意されており、

@require: code-printer/code-theme

で読み込んだパッケージ(提供モジュール名はCodeTheme)で20個強提供されています。詳細はドキュメントを見ていただくとして、一例を挙げるとこのようになっています。文字色やフォント、背景色を変更することができます。

f:id:puripuri2100:20211201201023p:plain
カラーテーマの例

例えば、SATySFiのコードをダークテーマで組みたいと思ったら

+code-printer ?:(
  CodePrinter.make-config CodeSyntax.satysfi CodeTheme.basic-dark
) (`let-mutable v-ref <- 0
let f x = x + 1
let g =
  let () = v-ref <- (f 1) in
  f !v-ref`);

みたいにすると

f:id:puripuri2100:20211201201054p:plain
貼り付けられたコードの例

のようになります。

全てのシンタックスとカラーテーマをみたい場合には“ドキュメントPDF”をお読みください。

その他のデザインの設定の仕方

設定用関数で継ぎ足すようにして設定を行っています。

例えば、行番号の表示を変更するには

+code-printer ?:(
  CodePrinter.make-config
  CodeSyntax.satysfi
  CodeTheme.basic-light
  |> CodePrinter.set-number-fun (fun ctx i -> (
    let ctx = set-text-color Color.black ctx in
    let number-it = i |> arabic |> embed-string in
    read-inline ctx {#number-it; 行目 }
  ))
) (`let x = 1 in
x * 2`);

のようにすると

f:id:puripuri2100:20211201201119p:plain
行番号変更のデモ

のように変更できます。

他にも

  • フォントサイズを編子する鵜機能
  • 行ごとに背景色を変更する機能
  • 改行マークの変更
  • タブ文字のサイズの変更
  • 枠などの装飾や周囲の余白の設定

ができるようになっています。

詳しくはドキュメントを読んでください。

オンライン上で読むには“ドキュメントPDF”をお読みください。

ローカルで見るには、

opam install satysfi-code-printer-doc

satyrographos install

を実行することでドキュメントファイルがビルドされて配置されます。

使用した技術・テクニックなど

設定の方法

デザインの設定には、今年に行ったSATySFi Conf 2021で紹介された「パイプライン演算子と関数を用いたDSL」を利用しました。

default ()
|> f1
|> f2
|> f3
...

という風にして設定を複雑化させていく手法です。Rustのライブラリでも採用されている手法です(clapなど)。

この手法では

  • 設定の順序を気にしなくて良い
  • 設定項目の増減を破壊的変更無しに実現できる
  • 見た目でわかりやすい

といった利点があります。

シンタックスハイライトを実現するために

正確なシンタックスハイライトを実現するには一からlexerを言語ごとに書いていく必要があります。しかし、そんなことをすると対応言語を増やすコストが増えてしんどくなります。

そこで、ある程度の正確性を犠牲にして簡単に設定できるようにしました。

  • 行コメント
  • ブロックコメント
  • 文字列
  • キーワード
  • 識別子

の5つそれぞれに対応するルールを書くだけで設定が終了するようになっています。ルールは主に正規表現で行うことになっています。

正規表現エンジンを自前で実装すると遅くなるので、SATySFi組み込みの正規表現エンジンを利用しています。これにより、他のシンタックスハイライトを実現するソースコード貼り付けパッケージに比べて圧倒的に早く処理が終わるようになっています。

string-scan : regexp -> string -> (string * string) optionというプリミティブを用いて解析を進めていきます。このプリミティブは

  • 与えられたregexpが先頭から続く文字列にマッチする場合はその文字列と残りの文字列を返す
  • マッチしなかった場合はNoneを返す

という役割を果たします。

たとえば、

let r = regexp-of-string `[0-9]+`

let s1 = `123abc456`
let v1 = string-scan r s1

let s2 = `abc456`
let v2 = string-scan r s2

としたとき、v1Some((`123`, abc456))になり、v2Noneになります。先頭から読んでいく解析にぴったりです。

これをルールを順番に適用していくことで、文字列がどの5つのルールに当てはまるのかを確認していき、トークンに変換します。また、そのとき同時にタブ文字・改行文字・スペースの解析もし、この2種類を専用のトークンに置き換えていきます。

この解析でコードがトークン列になるので、あとはカラーテーマの設定に従って組んでいくだけです。

一行が長いコードのための工夫

たまに一行が長すぎてはみ出てしまうコードが存在します。

これに対応するために、

  • ハイフネーションを完全に無効化
  • 適切な位置で問答無用で改行されてほしい
  • 改行箇所に改行マークなどを入れられるようにしたい

という3つの要望を満たしつつ、改行ができるように実装しました。

SATySFiにはdiscretionaryという「行分割の候補位置を作成する」プリミティブが存在します。このプリミティブには

  • 行分割されなかったときの挙動
  • 行分割されたときの、分割位置の直前に入れるブロック
  • 行分割されたときの、分割位置の直後に入れるブロック

の3つを指定することができます。これを用いることで上記の3つの要望を全て満たすことができます。

手法としては「コードを一文字ずつ分割してブロックし、discretionaryによって生成された分割候補位置を間に挟み込んでいく」というものです。

これによって、ハイフネーションを無くし、適切な位置で改行させることができます。また、分割位置の前後にブロックを入れられるため、改行マークなどの描画もできるようになります。

おわりに

コードを綺麗に貼り付けるためのSATySFi用のパッケージを作成しました。

かなり高機能なので使っていただけると嬉しいです。

パッケージ同士の機能ごとの切り分けや依存関係の調節など、大変なこともありました。

しかし、結果としてかなり満足な機能に仕上がり、とても嬉しいです。

大学への出願後の解放感で作成したパッケージなので、満足な仕上がりで良い題材になるのにも関わらず、自己推薦書に書けなかったという後悔があります(まぁ良いのですが)。

各言語用のシンタックスを登録するためにかなり多くの言語の公式ドキュメントを読み漁りました。言語によって行きつきやすさがかなり違いました。ここら辺は学ぶところがありますね。もし、言語のシンタックスルールが間違っている箇所がありましたら、プルリクエストを送っていただけると嬉しいです。

色覚異常があっても見やすいカラーテーマを考えるのも大変でした。結局色だけではなくフォントも変更することで判別しやすくしました。ここら辺はもうちょっと考えていきたいところですので、ご意見お待ちしております。

以上、シンタックスハイライトが効くコード貼り付けパッケージの紹介でした!

サイトを作ったので備忘録

はじめに

自サイトを作ったのでその時のことについてまとめました。

ハマりポイントがいくつかあったので、次も同じミスをしないために残します。

構成

ドメインValue Domeinで取得し、サーバーはさくらVPSにしました。

さくらのVPSはとりあえず

  • SSD 25GB
  • 仮想1Core
  • 512MB メモリ
  • Ubuntu 20.04LTS

という感じで、7078円/年です。

ドメインsiteで取って、4年で9914円になりました(主張が入らないドメインで、値段がそこそこなものを選んだつもりだったのですが、やはり高そうなのでしっかりと運営するドメインは別に取ろうかな、とも思っています)。

SSH接続

メインで使用しているWindows10機で既にSSHキーを作成してGitHubなどで使っていたため、さくらのインターネットのサイトに登録してすぐ使えました。

Tera Termというソフトウェアを使って接続しています。

最初ログインするときに、デフォルトのユーザー名がubuntuなことに気が付くまでに少し時間がかかりました(各OSによって違うらしく、他のものではrootである場合もあった)

接続後はadduserコマンドを用いて自分用のアカウントを作成し、それを用いて作業するようにしています。

参考(たぶん): https://knowledge.sakura.ad.jp/8218/?gl=11p632zlgcl_aw*R0NMLjE2MzY0NjkyMTMuQ2p3S0NBaUExYWlNQmhBVUVpd0FDdzI1TVJQY1FMNlVkcG5OVVJjaEhCYkpja3Rndnh1TDEzaWpPOHJad1BZbHJYS25Ldk9DNm12WU14b0NrdndRQXZEX0J3RQ..&ga=2.173555427.1772821998.1636464381-828121902.1634222933&gac=1.251234036.1636469213.CjwKCAiA1aiMBhAUEiwACw25MRPcQL6UdpnNURchHBbJcktgvxuL13ijO8rZwPYlrXKnKvOC6mvYMxoCkvwQAvD_BwE

apacheのインストール

パケットフィルタの設定を変更したあとに

$ sudo apt install apache2

apacheをインストールし、/var/www/puripuri2100.siteディレクトリを作成してその中で作業を行うようにしました(root権限を必要とした方がセキュリティ的に良いんですかね?)。

そしてconfファイルを/etc/apache2/sites-available/puripuri2100.site.confとして作成し、色々と設定を書きました。その後、このファイルを有効化してapacheを起動したところ、無事にページが表示されました。

参考にした記事: https://elec-hobby.com/vps-vol-03-apache/

https化

「さくらのSSL」を使ってみました。

申し込み時にopensslを使ってkeyファイルなどを生成します。

サーバー証明書をダウンロードして指示にある場所に配置し、認証されたらCRTファイルなどをダウンロードして配置し、ファイルのpathをconfファイルに書いたりしました。

HTTPからの接続も許可したかったのでVirtualHostでの設定を80番と443番でわけました。

$ sudo a2enmod ssl

をしてmod_sslを許可しないといけないのがハマりポイントでした。

また、HTTPで接続して来たら自動でHTTPSに飛ばすようにもしました。80番の方の設定に書き換え設定を書き、

$ sudo a2enmod rewrite

で書き換えモジュールを有効化して終了です。

設定を終えたら

$ sudo systemctl restart apache2

で再起動して終わりです。

参考にした記事:

https://www.rough-and-cheap.jp/linux/apache2_jprs_ssl_registration/

https://jp.globalsign.com/support/allssl/552.html

独自のパッケージマネージャによってインストールされたWSL上のコマンドをWindowsから呼び出す方法

WindowsからWSL上のコマンドを呼び出す一般的な方法

WSLにインストールしたコマンドをWindowsから呼び出したくなるときがあります。

適当に調べると

wsl ls -aのように、wslコマンドの後ろに普通にコマンドを書けば実行できるよ

と紹介する記事などが沢山出てくると思います。

実際、wsl --helpとしたときに、一番上に

使用法: wsl.exe [引数] [オプション...] [コマンドライン]

Linux バイナリーを実行する引数:

コマンド ラインがない場合、wsl.exe は既定のシェルを起動します。

--exec, -e <コマンドライン> 既定の Linux シェルを使用せずに、指定されたコマンドを実行します。

と表示され、Microsoftの公式サイトでも"Run Linux tools from a Windows command line"という項目が存在し、

For example:

C:\temp> wsl ls -la <- contents of C:\temp ->

という例が出てきます。

勿論、手元で

> wsl ls

とするときちんとファイルやフォルダが表示されます。

WSL上のコマンドが呼び出せない……?

さて、ここでRustというプログラミング言語コンパイラであるrustcコマンドを実行させてみたいと思います(勿論、WSL上にインストールしてあるコンパイラです)。

> wsl rustc --version

すると、結果は

/bin/bash: rustc: command not found

となります。

あれ……?

WSL上ではしっかりとrustcはインストールしてあり、試しにWSLを起動してそのうえでバージョンを確認してみるとしっかりと表示されます。

> wsl
$ rustc --version
rustc 1.54.0 (a178d0322 2021-07-26)

これはrustfmtcargorustupなどでも発生しました。

また、OCaml関連でインストールしたdunemenhirといったコマンドも同じく、command not foundと怒られてしまいました。

ところが、OCamlのパッケージマネージャであるopamWindows側から起動させることができました。

つまり、Windowsからwsl <command>構文を使って起動させることができるものと、起動させられないものが存在するのです。

解決方法(とりあえずの)

呼び出すことができないrustcと呼び出すことができるopam、という点に着目しました。

whichコマンドを使ってそれぞれのバイナリファイルの置き場所を見てみました。すると

$ which rustc
/home/puripuri2100/.cargo/bin/rustc

$ which opam
/usr/local/bin/opam

$ which ls
/usr/bin/ls

となりました。

どうやら、/usr/bin/以下か/usr/local/bin/以下のフォルダに実行ファイルが存在すると呼び出せそうな雰囲気があります。

というわけで実行ファイルを/usr/local/bin/以下にコピーしたいのですが、そのままコピーするとバイナリファイルをアップデートした際に困ります。なので、これを回避するためにシンボリックリンクを設置することにしました。

シンボリックリンクlnコマンドによって設置できますので、以下のようにして設定してみました。

$ sudo ln -s /home/puripuri2100/.cargo/bin/rustc /usr/local/bin/rustc

さて、ここで試しにWindows側から呼び出してみます。

> wsl rustc --version
rustc 1.54.0 (a178d0322 2021-07-26)

今度はきちんと表示されました。

どうやら「/usr/local/bin/以下に実行ファイルへのシンボリックリンクを貼る」という解決方法は一応機能するようです。(その後、rustcをアップデートした後にもう一度Windows側から呼び出してみると、きちんと動作しました。)

まとめ

  • WindowsからWSL上のコマンドを呼び出すにはwsl <command>という使い方をすれば良いが、それでも呼び出すことができないものが存在する
  • wsl <command>をすると、/usr/bin/usr/local/binなどしか見に行かないため、パッケージマネージャ独自のフォルダに実行ファイルが入っている場合は呼び出すことができない
  • /usr/local/bin以下に起動したい実行ファイルへのシンボリックリンクを設置することでWindowsからの呼び出しができるようになる
  • 実行ファイルへのリンクができただけなので、それ以外のライブラリ関係についてなどはよくわかりません
  • 公式情報が欲しいですね

learn-satysfiの紹介

これは「SATySFi Advent Calendar 2020」の25日目の記事です。

24日目はmonaqaさんによる「今年作ったパッケージを振り返る」でした。


21日目のgfnさんの記事がまだ出ていないですが、一応25日目を迎えることができましたね!(遅刻しましたが……)

SATySFi Advent Calendarは今年で3回目となります。 参加してくださった多くの方々に感謝いたします。

さて、今回は「learn-satysfi」を紹介しようと思います。

(本当は12月中に中身をもっと充実させるつもりだったのですが、精神状態が悪くなって記事が全く書けてませんでした)

目標

これは「SATySFiを学ぶためのドキュメント」というコンセプトのもと作っている文書です。

GitHub上で公開し、作成を行っています。リポジトリは「puripuri2100/learn-satysfi」です。

starを押していただけるとモチベーションが上がります。

この文書はRustのThe Rust Programming Languageのようなものを目指しています。

  • メンテナンスがしっかりとされており、最新版の情報をしっかり記述する
  • 本当の初心者が文書やパッケージを作れるようになる知識を提供する
  • 言語の詳しめな部分まで踏み込んで解説する

を一つの目標としています。

また、現在は日本語で書いていますが、将来的にはこれらを翻訳して英語版も作りたいと思っています。

執筆方法

原稿はMarkDownで書いています。

Rust製のソフトウェアであるmdbookを用いることでこれらの原稿をHTMLファイルに変換し、ブラウザで見ることができるようになります(使わなくても普通のMarkDownとして読み書きできます)。

リポジトリをforkして変更を加え、プルリクエストを送っていただければ取り込みますので、積極的に送っていただけると嬉しいです。

今後について

現在執筆は途中までしか進んでいませんので、記事を充実させていきたいと思います。

SATySFiでトンボと裁ち落としを設定するパッケージを作った話

これは「SATySFi Advent Calendar 2020」の6日目の記事です。

5日目はmonaqaさんによる「SATySFi で湯婆婆」でした。

6日目はabenoriさんのSATySFiで可換図式です。


「ネタがないなら今年作ったパッケージについて語ろう」ということで、自作パッケージを宣伝する記事第二弾です。

今回はSATySFiでトンボと裁ち落としを簡単に付けるためのパッケージを紹介したいと思います。

作ったものについて

クラスファイルの中を少し変更するだけでトンボや裁ち落としを付けることができ、さらに裁ち落としのサイズやトンボを付けるか付けないかなどを自由に弄ることができるような機能を提供するパッケージを作りました。

パッケージのリポジトリは"puripuri2100/satysfi-tombo"にあります

実際に使ってみるとこのようになります(実際には色はつきません)。

f:id:puripuri2100:20201212110250j:plain

薄い灰色部分の本文の周りに暗い縁で3mm幅の裁ち落としが付けられ、さらにトンボもついているのがわかると思います。

使い方

インストールは

opam install satysfi-tombo
satyrographos install

によってインストールできます。 提供されるパッケージファイルはtombo/tombo.satyhで、モジュール名はTomboです。

クラスファイル内での使用を想定しており、一般の文書作成者が触ることは想定していません(クラスファイルから作る場合は触るでしょうが)。

クラスファイルにおいてdocument型を生成するために使われるpage-breakプリミティブをTombo.page-break関数に置き換え、context型の引数を最初に追加で与えるだけで、生成されるPDFに裁ち落としとトンボが付いてきます。

具体的には、普通クラスファイルの中で

page-break page pagecontf pagepartsf bb-main

のようにしてdocument型を作っている部分を

Tombo.tombo-page-break ctx-doc page pagecontf pagepartsf bb-main

のように変更するだけです。

二段組にも対応していて、

Tombo.tombo-page-break-two-column ctx-doc page len f pagecontf pagepartsf
bb-main

とするだけで出来ます。

オプション引数で裁ち落としのサイズとトンボのための余白の大きさを変えることができます。

Tombo.tombo-page-break ?:(Some(<裁ち落としの長さ:length>)) ?:(Some(<余白の大きさ:length>)) ctx-doc page ...

一番目が裁ち落としの長さで、二番目が余白の大きさです。

どちらもlength optionで与えます。一番目にNoneを与えると裁ち落としが設定されなくなり、二番目にNoneを与えるとトンボが付けられなくなります。

作った動機

私用で印刷所に入稿するPDFデータをSATySFiで作ることにしたため、必要になると思い作成しました。

「進捗大陸」というSATySFiで同人誌を作成しているサークルでは手動でページサイズを3mmずつ増やしていたりするらしいですが(参考:進捗大陸6「SATySFiで技術同人誌を作ろう」 by amutake)、そこでも指摘されている通り、PDFを配布したいときなどの裁ち落とし等を設定しない場合との切り替えが面倒であったりするので、そこら辺の面倒を無くしたい気持ちが結構ありました。

実装方法

page-breakには

  • ページサイズ
  • ページ番号を受け取って本文の高さと本文の開始座標を返す関数
  • ページ番号を受け取って
    • ヘッダーの中身
    • ヘッダーの開始位置の座標
    • フッターの中身
    • フッターの開始位置の座標

を返す関数

を与えます。

そこで、この3つの値に対して

  • ページサイズを裁ち落としとトンボの余白大きくした値を設定しなおす
  • 本文・ヘッダー・フッターの開始位置の座標をそれぞれ大きくする余白分ずらす

という操作を行います。

これで裁ち落としの設定ができました

あとはトンボのグラフィックを用意し、それを描画させるだけです。

グラフィックを用意しても、それが評価されないと出力されないので、

inline-graphics 0pt 0pt 0pt (fun _ -> tombo-gr)

のようにして大きさの無いinline-boxesを作り、これをblock-boxesに変換した後にヘッダーの下などに付けておくようにします。

こうすることで全てのページでトンボを描画する関数が評価され、トンボが出力されることになります。

もっと詳しく知りたい人はコードを読んでください。

課題

現状SATySFiはPDFの書き出しでMediaBoxしか設定できません(これはSATySFiがPDF書き出しに使用しているcamlpdfを弄れば実現できるかもしれません)。

そのため、「裁ち落とし」や「トンボ」と言ってもBleedBoxやTrimBoxが設定されているわけではないため、ある意味「飾り」と言っても過言ではない状況になっています(裁ち落としに関しては実用性はそこそこありますが)。

将来SATySFiがMediaBox以外も書き出せるようになったらここに対応したいと強く思っています。

また、page-breakをラップして実装しているため、graphicsの座標指定で絶対座標を使っている場合は大きくズレてしまうという欠点も抱えています。

さいごに

(様々な都合で)実用できるか微妙なところのSATySFi-tomboですが、どうやら自分が使う予定である用事では「トンボは付けず、3mmの裁ち落としと塗り足しを設定すること」という印刷所からの指定への対応としては使えそうです(3mmである前提で印刷所が作業をするのでTrimBoxなどを設定してなくても大丈夫、とのことでした)。

入稿の設定によってはこのパッケージが使える場面はあると思いますので、使っていただけると嬉しいです。