マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

scsnowmanでつくる対称コルーチン(※最新の定義)

猛暑! 台風! ゆきだるま☃︎

コルーチンのイロイロな定義

某ZR氏の某ツイッタァーをフォローしている方ならご存知だと思いますが、去る5月30日に、某出版社の某『n月刊ラムダノート』の創刊を記念したパーティーが催されました。

このパーティーにおいてメインのテーマとなったのが、

コルーチンの定義がイロイロありすぎてアレ

ということでした。この話題についての詳細は以下の記事に譲ることにしますが、要するにコルーチンの定義が本質的に問題なわけです。

コルーチンの素敵な定義

この問題に対して、そのパーティとは全然サッパリ関係のない某ZR氏が、画期的な解決法を提案しています。

スバラシイ☃︎

scsnowmanで対称コルーチン(※最新の定義)したい話

せっかくコルーチンの定義が素敵☃︎になったのですから、LaTeXのscsnowmanパッケージを使ってコルーチン(※最新の定義)に関する技術文書を作りたくなりますね。ところが、ここで大きな問題があります。それは、

対称コルーチン(※最新の定義)は対称でないといけない

ということです。

f:id:zrbabbler:20190808163349p:plain
対称コルーチン(※最新の定義)

一方で、scsnowmanで出力されるゆきだるま☃︎は、どれも素敵ですが非対称です。

かの画期的なscsnowmanパッケージも対称コルーチン(※最新の定義)はサポートできないのでしょうか。いや、決してそんなことはありません。実は、scsnowmanには「ゆきだるま形状をユーザが独自に定義する」ための機能が用意されています。

Any users can define and use custom snowman shape definitions. Here is a description of adding a shape named myfavorite.
  1. Prepare a snowman definition file scsnowman-myfavorite.def and put it into $TEXMF tree (e.g. texmf-local/tex/latex/scsnowman/). (後略)
  2. (scsnowman マニュアル; §6 “Adding User-defined Snowman Shapes”)

つまり、対称なゆきだるま形状を定義したファイルscsnowman-zrsymmetric.defを用意すれば、次のようにして対称なゆきだるまが出力できるはずです。

% pdfLaTeX document
\documentclass[a4paper]{article}
\usepackage{scsnowman}% ゆきだるま!
\usescsnowmanlibrary{zrsymmetric}% 対称!
\begin{document}
% 'shape'キーで形状を指定する
\scsnowman[shape=zrsymmetric,‹他オプション›...]
\end{document}

scsnowmanで対称コルーチン(※最新の定義)する話

というわけで、作ってみました

早速、対称コルーチン(※最新の定義)をつくってみましょう。

% upLaTeX文書
\documentclass[uplatex,dvipdfmx]{jsarticle}
\usepackage[a6paper,scale=0.75]{geometry}
\usepackage{xcolor,scsnowman}
\usescsnowmanlibrary{zrsymmetric}% 対称ゆきだるま
\begin{document}
非対称コルーチン
\scsnowman[hat=green!35!black,arms=green!20!black,
buttons=green!35!black,snow,muffler=green!50!black,
adjustbaseline,scale=2]% フツー(非対称)
も、対称コルーチン
\scsnowman[hat=green!35!black,arms=green!20!black,
buttons=green!35!black,snow,muffler=green!50!black,
adjustbaseline,scale=2,shape=zrsymmetric]% 対称!
もどちらも素敵なので、
両者は等価です。
\end{document}

f:id:zrbabbler:20190808180932p:plain
コルーチン(※最新の定義)に関する技術文書

バッチリですね!

イロイロな対称ゆきだるま

形状オプションshape=zrsymmetricを付けた場合でも、\scsnowmanの他のオプション(hatmuffler、などなど)は自由に設定できます。

% pdfLaTeX document
\documentclass{article}
\usepackage[a6paper,scale=0.75]{geometry}
\usepackage[svgnames]{xcolor}
\usepackage{scsnowman}
\usescsnowmanlibrary{zrsymmetric}% 対称!
%% \CompareSnowmen{<オプション>...}
% 非対称と対称のゆきだるまを並べて出力する.
\newcommand{\CompareSnowmen}[1]{\par
  \scsnowman[scale=4,#1]%
  \scsnowman[scale=4,shape=zrsymmetric,#1]%
  \par\smallskip}
\begin{document}
% シンプル
\CompareSnowmen{hat,arms,snow,muffler}
% ミカン付き
\CompareSnowmen{mouthshape=tight,
  mikan=Orange,leaf=Olive,sweat=SkyBlue}
% 箒付き
\CompareSnowmen{hat=Green,arms=Brown,muffler=Red,
  buttons=Blue,snow=SkyBlue,broom=DarkGoldenrod}
\end{document}

f:id:zrbabbler:20190808181012p:plain
イロイロな対称ゆきだるま(非対称もあるよ)

scsnowmanのゆきだるまの多様性がもっともっと増えたわけですね。スバラシイ☃︎

まとめ

というわけで、非対称コルーチン(※最新の定義)も、対称コルーチン(※最新の定義)も、それ以外のゆきだるま☃︎も、すべて素敵!

Markdownでデカイ文字を書けて便利な話(ただしPandoc)

聞くところによると、Markdownでとにかくデカイ文字が簡単に書けると便利なようです。

しかし残念なことに、元来のMarkdownは意味的なマークアップを指向したものであるため、今世にあるMarkdownの各種方言はどれも「見出しを書く」ことができても「デカイ文字を書く」ことができません。このことがデカイ文字の熱狂的ファンがMarkdownの採用を躊躇する一因となっていることは否めないでしょう。

というわけで、Markdownでデカイ文字を書くためのPandocフィルタを作ってみました

文字をデカくする

このフィルタを使う場合、デカイ文字は「bigクラスをつけたspan要素」として表されます。Pandoc Markdownの記法では次のように書きます。

[sample1.md]

Pandocは[アレ]{.big}。

早速このMarkdownをHTMLに変換してみましょう。

pandoc sample1.md --lua-filter biggggg.lua -s -o sample1.html

f:id:zrbabbler:20190731210533p:plain
HTMLでデカイ文字

デカイ! 便利!

今度はLuaLaTeX経由でPDFに変換してみましょう。

pandoc sample1.md --lua-filter biggggg.lua -o sample1.pdf --pdf-engine=lualatex -V documentclass=bxjsarticle -V classoption=pandoc

f:id:zrbabbler:20190731210622p:plain
PDFでデカイ文字

デカイ! 便利!

※現状では、対応する出力形式はHTMLとLaTeX(経由のPDF)に限ります。

文字をもっともっとデカくする

「これだけのデカさでは物足りない」という人はもっともっとデカイ文字も使えます。クラス名としてbigの代わりにbiggbigggbigggg、……とすることで、文字をどんどんデカくできます。

[sample2.md]

Pandocは[アレ]{.bigg}[アレ]{.bigggg}
[アレ]{.bigggggg}[アレ]{.bigggggggg}。

※見やすさのため、Markdown中に改行を入れました。この改行は(空白にならずに)無視されてほしいので、pandoc実行時にオプションに-f markdown+ignore_line_breaksを追加することにします。

f:id:zrbabbler:20190731210654p:plain
HTMLでもっともっとデカイ文字
f:id:zrbabbler:20190731210716p:plain
PDFでもっともっとデカイ文字

もっともっとデカイ! 便利!

強調文字もデカくする

もちろん、デカイ文字を他の文字装飾と組み合わせることもできます。

[sample3.md]

Pandocは[アレ]{.bigg}、TeXは[超絶**アレ**]{.bigggggg}。

f:id:zrbabbler:20190731211010p:plain
HTMLでデカイ強調文字
f:id:zrbabbler:20190731211035p:plain
PDFでデカイ強調文字

強調付きでデカイ! 便利!

まとめ

Pandocはネタ記事を書くのに便利!(えっ)

PandocでWindowsをシャットダウンする件について

皆さんもよくご存知の通り、LuaLaTeXでは「Windwosをシャットダウンする文書」が作成できます。これはLuaコードを通じて(C言語コンパイルして生成した)マシン語のプログラムが実行できることを利用しています。

ところで、以前のネタで紹介した通り、PandocではLuaでフィルターを実装することができます。となると、マークダウンという不思議な形式の文書でWindowsをシャットダウンしてみたくなるのは当然の帰結でしょう。

どうもPandocでWindowsをシャットダウンできそうにない件

Luaでバイナリ(マシン語)のモジュールを作製する際には、次のような感じのC言語の関数を実装します。

※以下のコードはLuaLaTeXのやつで使っているモジュール1ソースコードからの抜粋。

/* Opens the module.
 */
__declspec(dllexport) int luaopen_shutwindown(lua_State *L) {
    luaL_newlib(L, registry);
    return 1;
}

Luaでモジュールを読み込む(require "shutwindown")と、この関数が実行されるのですが、この中で使われているluaL_newlibというのは「Lua処理系の連携用API」の一つです。連携APILua処理系と外部のコードの間のやり取りを行う機構で、バイナリのモジュールの実装に不可欠なものです。

つまり、バイナリのモジュールを動作させるには、Lua処理系の連携APIの関数が「外から見えている」必要があるわけです。TeX Live配布におけるLuaTeXのLua処理系は動的リンクのライブラリ(WindowsだとDLL形式)になっているため、連携APIは外から見えています。これに対して、Pandocの公式のWindwos用バイナリではLua処理系が静的にリンクされていて連携APIが外から見えません。これではLuaTeXの時と同じようには「Windowsをシャットダウンするモジュール」を実装することはできません。

それでもPandocでWindowsをシャットダウンしたい件

絶望的な状況になっていしまいましたが、もう少し考えてみましょう。

先程述べた通り、Luaコードにおいてモジュールshutwindownの読込(require)を行うとC言語の関数luaopen_shutwindownが呼ばれます。Luarequire "shutwindown"に対応する動作なので、通常はこの関数では「モジュールの関数を収めたLuaテーブルを作成して返す」ことが期待されています。しかし、とにかくモジュールの実装コードに実行を移すことができているのだから、ここで早々とシャットダウン開始の処理を済ませてしまえばいいわけです。

/* Opens the module.
 */
__declspec(dllexport) int luaopen_shutwindown(void *L) {
    shutdown_system(); /* シャットダウン! */
    return 0;
}

すなわち、このモジュールがインストールされたLua処理系では、require "shutwindown"を実行するだけでシャットダウンが開始します。

改めてPandocでWindowsをシャットダウンする件

というわけで、作ってみました

このリポジトリにあるファイルpcshutwindown.dllとshutdown.luaをカレントディレクト2に置いた上で、何か適当なMarkdown文書’(リポジトリにあるREADME.mdでもいいでしょう)をPandocで変換しましょう。もちろんフィルタにshutdown.luaを指定することを忘れずに。

C>pandoc README.md --lua-filter shutdown.lua
System will be shutdown in 10 seconds...
System will be shutdown in 9 seconds...
System will be shutdown in 8 seconds...
System will be shutdown in 7 seconds...
System will be shutdown in 6 seconds...
System will be shutdown in 5 seconds...
System will be shutdown in 4 seconds...
System will be shutdown in 3 seconds...
System will be shutdown in 2 seconds...
System will be shutdown in 1 second...
FAREWELL!

f:id:zrbabbler:20190616011206p:plain

まとめ

結局、PandocのLuaフィルタでバイナリモジュールを利用するのは難しい、のかな?


  1. 当該の記事を書いたときには、当時のLuaTeXに合わせてLua 5.1版を前提にした実装でしたが、現在(TeX Live 2019以降)のLuaTeXのLua処理系は5.3版であるため、5.3版で動作するように改修しました。

  2. Pandocの公式バイナリではLuaのバイナリモジュール読込パスにはカレントディレクトリが含まれています。

「サイゼリヤで1000円あれば最大何kcal摂れるのか」をSATySFiで解いてみた

SATySFiをオワコンにしてしまうのは忍びないので、やってみた

作ったもの

このsaizeriyaパッケージを使うとSATySFi文書中でサイゼリヤ問題ができるようになる。

[saizeriya-test.saty]

@require: stdja
@require: saizeriya
%saizeriya.satyhをカレントに置く場合は↓を使う
%@import: saizeriya

%------------------------------------------------- メニューデータ
let the-menu = [
(|calorie=130;cost=299;name=`彩りガーデンサラダ`|);
(|calorie=115;cost=349;name=`小エビのサラダ`|);
(|calorie=134;cost=299;name=`やわらかチキンのサラダ`|);
(|calorie=92;cost=299;name=`わかめサラダ`|);
……(中略)……
(|calorie=164;cost=369;name=`トリフアイスクリーム`|);
]
%------------------------------------------------- 本文
in

document (|
  title = {\SATySFi;でサイゼリヤ問題};
  author = {某ZR(アレ)};
  show-title = true;
  show-toc = false;
|) '<                                          
  +section{問題}<
    +p{
      予算1000円以内で,サイゼリヤで最大カロリーを摂取するような
      注文の仕方を求めよ。
      ただしサイゼリヤの料理のメニューは以下の通りとする。
    }
    %the-menuのメニューを箇条書きで出力する
    +saizeriya-listing-menu(the-menu);
  >
  +section{解答}<
    +p{
      以下の通り。
    }
    %サイゼリヤ問題を解いて解答を表組で出力する
    +saizeriya-tabular-solution(the-menu)(1000);
  >
>

この文書をコンパイルすると次の出力が得られる。

※SATySFiの0.0.3版を使用。

f:id:zrbabbler:20190528215346p:plain
「問題」の出力の冒頭

f:id:zrbabbler:20190528215409p:plain
「解答」の出力

まとめ

というわけで、SATySFiは非オワコンで素敵!

「サイゼリヤで1000円あれば最大何kcal摂れるのか」をPandocで解いてみた

どうやら、TeXを使うと計算と組版を一気にやってしまえて最高、なようです。

ところで、皆さんご存知の通りTeXアレなわけですが、どうやら聞くところによると、Pandocも相当アレなようです。

となると、サイゼリヤで1000円あれば最大何kcal摂れるのか」をPandocで一気に計算して組版する、というネタがあって然るべきなのは、当然の帰結でしょう。

というわけで、やってみました

方針

サイゼリヤ問題を解くMarkdown文書

[sample.md]

# 問題

予算1000円以内で,サイゼリヤで最大カロリーを摂取するような注文の仕方を求めよ。ただしサイゼリヤの料理のメニューは以下の通りとする。

[一覧](./menu.csv){.saizeriya-list}

# 解答

以下の通り。

[解答](./menu.csv){.saizeriya-solve badget=1000}

[menu.csv]

彩りガーデンサラダ,130,299
小エビのサラダ,115,349
やわらかチキンのサラダ,134,299
わかめサラダ,92,299
イタリアンサラダ,196,299
……(略)……

書式の説明

特定のクラスを付けたリンク要素を書くと、その部分がフィルタによって置き換えられます。

次のように、クラスにsaizeriya-listを指定したリンクを書くと、指定のメニューファイルを読み込んでメニューの一覧の箇条書きを生成してその場に出力します。(テキストは出力されません。)

[テキスト](メニューファイルのパス){.saizeriya-list}

クラスにsaizeriya-solveを指定したリンクを書くと、指定のメニューファイルを読み込んでサイゼリヤ問題を解き、その解答を表組にしたものを出力します。この際に予算額badgetという属性で指定します。

[テキスト](メニューファイルのパス){.saizeriya-solve badget=予算額}

さっそくPandocしてみる

以下のコマンドで、先のMarkdown文書(sample.md)をWord文書に変換します。

pandoc sample.md --lua-filter=saizeriya.lua -o sample.docx

※「Wordは嫌だ」という人は、出力ファイル名のsample.docxの拡張子を変えて別の形式を選びましょう。例えばsample.odtとするとOpenDocument形式になります。sample-out.mdのようにすると別ファイルにMarkdown形式で出力できます。

出力されたWord文書(sample.docx)を開いてみると、メニュー一覧が正しく挿入されていることが判ります。

※以下の出力結果はPandoc 2.7.2(最新版)によるものです。

f:id:zrbabbler:20190525154330p:plain
sample.docx 1ページ目冒頭

そして、最後のページをみると、例の栄養満点な3点セットが、無事に出力されていました。

f:id:zrbabbler:20190525154405p:plain
sample.docx 4ページ目

まとめ

たとえTeX言語ができなくても、Pandocがあれば計算と組版を一気にやれます! スゴイ!(えっ)

決定版! TeX のインストール・設定方法

皆さん、技術書を読みましょう!

お使いのコンピュータに TeX 環境を整える

[改訂第7版]LaTeX2ε美文書作成入門

[改訂第7版]LaTeX2ε美文書作成入門

オンラインの TeX / LaTeX サービスを利用する

インストールいらずのLATEX入門  ―Overleafで手軽に文書作成

インストールいらずのLATEX入門 ―Overleafで手軽に文書作成

以上!

完璧!! #えっ

Pandocで(u)pLaTeXしてみる話

どうやら、新しいPandocではビルドにLatexmkが使えるらしい。

  • Add latexmk as an option for --pdf-engine (#3195). Note that you can use --pdf-engine-opt=-outdir=bar to specify a persistent temp directory.

Pandocの「PDF出力エンジン」(--pdf-engine)として指定できるLaTeXエンジンはpdfLaTeX、XeLaTeX、LuaLaTeXに限られている。しかし、Latexmkが使えるようになったということは、これを利用して「(u)pLaTeX+dvipdfmxでPDFを生成する」ことができるはずである。

PandocでLatexmkしてみる

とりあえず、簡単な英語のMarkdown文書を用意して試してみる。

[test1.md]

# Welcome!

Hello, Pandoc *chaos*!

これを--pdf-engine=latexmk付のpandocで変換する。

※プロンプトを>で表す。

> pandoc --pdf-engine=latexmk test1.md -o test1.pdf
Latexmk: Run number 1 of rule 'pdflatex'
Latexmk: Run number 2 of rule 'pdflatex'

f:id:zrbabbler:20190506233335p:plain
test1.pdfの内容

フツーにPDFが出力できた。端末表示をみると、どうやらpdfLaTeXを使うワークフローが選択されているようである。実際、出力PDFの文書情報のProducerの値もpdfTeX-1.40.20となっている。

さらに細かく挙動を調べてみると、以下のようになっているようだ。

  • latexmk起動時に-pdfオプションが指定されている1
  • latexmk実行時にカレントディレクトリは変更されていない。
    • Latexmkの-outdirオプションでLaTeXの出力先を変えている。
    • 従って、カレントにlatexmkrcがある場合は読み込まれる。
    • ただし、latexmkrc内に$pdf_modeの設定を書いても、起動オプションの-pdfにより上書きされて、常に$pdf_mode=1となる。

Pandocで(u)pLaTeXする方法

以上のことから考えると、「Pandocで(u)pLaTeX+dvipdfmxを使う」ためには以下のようにすればよいことがわかる。

  • pandocコマンドのオプションに-pdf-engine=latexmkを指定する。
  • latexmkのオプションに-pdfdviTeX→DVI→PDFのワークフローを指定)を追加するために、pandocのオプションに--pdf-engine-opt="-pdfdvi"も指定する。
  • カレントにlatexmkrcを置いて、そこに(u)pLaTeX+dvipdfmxを使うための設定を書く。

つまり、Pandocのコマンド行は以下の形になる。

> pandoc --pdf-engine=latexmk --pdf-engine-opt="-pdfdvi" ......

latexmkrcの内容は(最低限として)以下のようにする。
※先述の通り、$pdf_modeの設定は効かないので不要。

upLaTeX+dvipdfmxの場合:

$latex = 'uplatex';
$bibtex = 'upbibtex';
$dvipdf = 'dvipdfmx %O -o %D %S';
$makeindex = 'mendex -U %O -o %D %S';

pLaTeX+dvipdfmxの場合:

$latex = 'platex -kanji=utf8';
$bibtex = 'pbibtex -kanji=utf8';
$dvipdf = 'dvipdfmx %O -o %D %S';
$makeindex = 'mendex -U %O -o %D %S';

もちろん、この設定はPDF生成に用いるコマンドを変更するだけのもので、PandocのLaTeXコード生成には何も影響を与えない。従って、ここで示したもの以外のPandocの設定は「途中で生成されるLaTeXファイルが(u)pLaTeXで通るようにする」必要がある。

実際にupLaTeXしてみた

例として、日本語のMarkdown文書をPandocのデフォルトのLaTeXテンプレートを通してupLaTeX+dvipdfmxのワークフローでPDFに変換してみる。デフォルトのLaTeXテンプレートは本来は(u)pLaTeXには対応していないが、BXjsclsのクラスのPandocモードであれば利用できる。

※もちろん、カスタムのテンプレートを指定してもよい。

[test2.md]

---
title: PandocでupLaTeXしたい話
author: 某ZR
documentclass: bxjsarticle
classoption:
  - pandoc
papersize: a5
---

# upLaTeXできると何がうれしいか

よくわからない。

※先頭にYAMLメタデータブロックを記述している。

これを次のコマンドで変換する。

> pandoc --pdf-engine=latexmk --pdf-engine-opt="-pdfdvi" test2.md -o test2.pdf
Latexmk: Run number 1 of rule 'latex'
Latexmk: Run number 2 of rule 'latex'
Latexmk: Run number 1 of rule 'dvipdf'

f:id:zrbabbler:20190506233146p:plain
test2.pdfの内容

別解

いちいちカレントにlatexmkrcを置くのは面倒である。代わりに、固定のディレクトリ(仮に/path/to/dirとする)にLatexmkの設定ファイルを置いた上でそれを-rオプションで読み込むという方法もある。

この場合、Pandocが生成するコマンド行において-rオプションが-pdfより後ろに置かれるため、設定ファイル内の$pdf_modeの記述で-pdfを上書きすることができる。従って、次のように$pdf_,modeを含めた設定ファイルを用意しておくとよい。

[/path/to/dir/uplatex-dpx.latexmk]

$latex = 'uplatex';
$bibtex = 'upbibtex';
$dvipdf = 'dvipdfmx %O -o %D %S';
$makeindex = 'mendex -U %O -o %D %S';
$pdf_mode = 3;

その上で、以下のコマンドを実行する2。(実際には改行なしの1行で入力する。)

pandoc --pdf-engine=latexmk
    --pdf-engine-opt="-r" --pdf-engine-opt="/path/to/dir/uplatex-dpx.latexmk"
    test2.md -o test2.pdf

まとめ

新しいPandocを使うと「Pandocで(u)pLaTeXする」のがチョットだけ楽になる、かもしれない。


  1. 実際のコマンド行は次の通り: latexmk -interaction=batchmode -halt-on-error -pdf -quiet -outdir=TEMPDIR TEMPDIR/input.tex;ここでTEMPDIRはPandocが生成した一時ディレクトリの名前。

  2. 一つの--pdf-engine-optでは一つのコマンド引数しか指定できないので、-r /path/to/dir/uplatex-dpx.latexmkというオプションを指定するには煩雑であるが--pdf-engine-optを2回書くしかないようである。