niszetの日記

アナログCMOS系雑用エンジニアが頑張る備忘録系日記

PandocでDivにCustom Styleをあてたときのnative形式の出力

とりあえず困ったらnative形式で見てみるべし。

さて、最近Luaフィルタをいじっていますが、やりたいことは特定条件下でいい感じのスタイルを適当に当ててくれるフィルタを作ることです。具体的にはCodeがfootnoteやHeadingsに入った場合に専用のスタイルを勝手に割り当てて欲しいわけです。もちろん、専用のスタイルはあらかじめWordのテンプレートの方に準備してやる必要がありますが。

…ということで、カスタムスタイルを当てた場合のnative形式での出力を確認してみる。

たとえばこんな感じの記述は

::: {custom-style="Poetry"}
aaa
:::

こんな感じになる。

,Div ("",[],[("custom-style","Poetry")])
 [Para [Str "aaa"]]

Divの下にPara、Paraの下にStrが来るようだ。単純にDiv直下に来るわけではない。ということで、各Block要素、Inline要素についてどの入力パタンであればどうなるかというのを一度見ておく必要がありそう。本当はHaskellのコードを読み解いた方が良いのだろうけども、それはそれで抜けがありそうなので。

ということで、一通り調べるとそれで1冊になってしまいそうですね。書きましょう、書きましょう…。

Enjoy!?

indented codeに行番号をつける

偶然見つけたので書いておく。

atusyさんのこの記事に関連して。

blog.atusy.net

Rのchunk内ではattributesを渡せない…?

前回書いた内容はMarkdownのfenced codeなどのcode系の記法が行番号を扱えるかどうか?の確認であって、Rのコードブロックで取り扱えるものではなかった。これは、Rのコードを実行後、その生成物をMarkdownに埋め込む処理をR/knitr/rmarkdownが対応しているが、コードの表示を行う('echo=True`)ようにしても、チャンクオプションとして与えられるのはclassのみだからであった。

今まで調べた範囲では、チャンクオプションとしてclassは与えられるものの、startFrom=10のような属性(attr)は与えられないようである。

もう少しコードも含めて調べてみるが望みは薄い。

属性をclassとして無理やり渡すことは出来るが、markdownをPandocに与える前に対応する必要がある。具体的には.startFrom=10というclassで与えられるので、これから.をとればよい。これはluaのfilterで対応できる(class名に=があった場合、先頭の.を取る、という方法で)

もちろんこれはpost knitのタイミングで対応しても良い。いずれにしてもPandocに渡す前に対応する必要がある。

一方で、Pandocはインデントされたコードブロックに対して、クラスを与えることが出来る。下記の、

--indented-code-classes=CLASSES

を与えればよい。具体的には、

output: 
  html_document:
    pandoc_args: 
      - --indented-code-classes
      - numberLines
    highlight: tango

とすることで、インデントされたコードブロックにnumberLinesというclassが与えられ、このclassを持ったコードブロックはhighlightが有効になっている場合は行番号が付与される。

ということを見つけたのだが、肝心のRの実行コードに対する行番号付与(正確には行番号の先頭の数字の付与)はこの方法では対応できないのであった。

使う場面があるのか不明なのだが、見つけたのでメモしておく。

Enjoy!!

JavaScriptを使ってR Markdownで生成したHTMLドキュメントに行番号をつける例

learnrパッケージにあった。

見つけたのでとりあえずのメモ。

learnr パッケージのサイトに行くと、コードが行番号付きで埋め込まれている。

rstudio.github.io

htmlのソースを読むと、jsで対応していることがわかり、コード自体はパッケージに含まれているようだ。

github.com

ということで、JavsScriptを使用して行番号を表示するのはこれを参考にする(あるいはライセンスに注意して流用する)ことで対応できそうである。

というメモ。

Enjoy!!

pandoc.Attrを使う際の注意

注意というか…仕様がわからない…。

結局、SOを見て解決した。

stackoverflow.com

ここにあるように、

attrs = pandoc.Attr("", {}, {{"lang", "es-SP"}})

と、3番目の引数は{{}}として囲わないとダメだった。理由はよくわかっていないが、動いたので正しい。tableのtableにする必要がある…?そんな記述どこにもなかったと思うのだけど…。

とりあえず、これで所望の挙動はしたので良いのだが、もうちょっと調べないといけませんね。

(Pandoc) inline_code_attributes option

またPandocの話。

すっかり忘れていたが、inlineのcode chunkであってもattributesを付与できる。

`plot()`{.r #hogge}

こんな感じに。Verbatim(Pandoc native的にはCode)扱いなのであるが、.rのように言語指定しておけば、highlight: tangoなどでハイライトされる。本文中にコードを埋め込みつつハイライトを有効にしたい場合は有効ではないかと思います。

Enjoy!!

Pandoc 2.7.2 に同梱されているLuaのバージョンの確認

簡単に書けるものなら色々作れそう。

さて、PandocのLuaフィルタについて少しずつ調べているのですが、簡単なものであればもう書けそうなので順次書いていく。

たとえば以下のような関数を作ってLuaフィルタとして使用する。

    function Str(elem)
      if elem.text == "{{LUA_VERSION}}" then
        return pandoc.Emph {pandoc.Str(_VERSION)}
      else
        return elem
      end
    end

で、Markdownの本文中に{{LUA_VERSION}}と書いておくと、変換後にここがLua 5.3となる。よって、Pandoc2.7.2に同梱されているLuaのバージョンは5.3であり、Programming in Lua Forth Editionに書かれていることを全部使えるということになる。

以上。

Enjoy!!

PandocのLuaフィルターを書いてみる

Luaの文法がまだ覚えきれていないのでまずはそっちを固めるべき

ひとまず、公式のマニュアルを読んだ。

pandoc.org

例はココにあるらしいが、まだ読んでいない。

github.com

また、通常のフィルターも少しだけ目を通したが、フィルタの実行環境を持っていない人にどうやって環境を渡すのかを考えるのが面倒なので、Pandoc2.0から本体に組み込まれ、そして他の言語よりも動作が速いと書かれていたLuaのフィルターを使うこととした。

pandoc.org

最近Luaの勉強をしていたのはそのためである ^[もうひとつ、FlashAirのためでもあるのだが]

マニュアルに書かれていないことが多くないですかね…。

とりあえずマニュアル読んだだけだと非常に簡単なものしか作れない。ちょっと習作ということで、強調を斜体に変更し、間にあるスペースを削除して詰めるフィルタを書いた。結果としてそうなったというだけで、はじめからそうしたかったわけではないのだが。

function Strong(elem)
  t = ""
  for k, v in pairs(elem.content) do
    if v.tag == "Str" then
        t = t .. v.text
    end 
  end
  return {pandoc.Emph(t)}
end

これで、**HU HU HU HU**と書いたものが*HUHUHUHU*と等価な出力となった。

この変換前の一文は

"C:/Program Files/RStudio/bin/pandoc/pandoc" -f markdown hoge.md -t native

のようにnative形式で出力すると

Para [Strong [Str "HU",Space,Str "HU",Space,Str "HU",Space,Str "HU"]]

に対応する。ここで、elem.contentはこの[Str "HU",Space,Str "HU",Space,Str "HU",Space,Str "HU"]を受け取ることになる。

さて、コードについて。function Strong(elem)でStrongが見つかったらこの関数をcallするような挙動 ^[実装がそうなっているのかは確認していない。]となる。ここでelemを引数に入れないとどうなるんだろ?あとでやってみる。

for文で各要素を見ていく。ここでkは要素のindex、vが実体になるようだ。この場合、ipairsの方が良いのかもしれない。あとでやってみる。

Spaceはtextを要素に持っていないのでnilが返る。nilと文字列は結合できないので先にvのtagがStrであることを確認している。もっと良い実装があるだろうけど。

  t = ""
  for k, v in pairs(elem.content) do
    if v.tag == "Str" then
        t = t .. v.text
    end 
  end

で、テキストを結合している。最初に空の文字列を与えないとこれまたnilとの結合になるので注意。Luaはundefinedは全部nilだ。

最後はtableにして返さないとダメっぽいが、ここは理由がちょっとよくわからない。他の例では大丈夫だったはずなのに。

  return {pandoc.Emph(t)}

ということで、はじめてのLuaフィルタの完成なのでした。

Word出力にする際にちょっとあれこれいじりたいところがあるので、Luaのfilterを使って何とかしたかったのですが、これならすぐできるかもしれないね。

Enjoy!!