m13o

2022-05-06 Fri 20:36
special-blockにパラメータを付けても無意味Emacs orgmode

org-mode のエクスポートバックエンドを構築する際、適切なブロックが存在しない場合に special-block を利用したくなる事があります。Org Syntax によると special-block は Greater Block の一種という扱いで、center、quote、以外で Lesser Block と呼ばれるブロック以外で以下のようなシンタックスを持つブロックの事を言うようです。

#+begin_NAME PARAMETERS
CONTENTS
#+end_NAME

先にも述べた通り、NAME は center、quote、そして Lesser Block と呼ばれる以下のブロック以外の任意の非ホワイトスペースな文字列が入ります。

  • comment
  • example
  • export
  • src
  • verse

CONTENTS はブロックの内容そのもので、PARAMETERS はこのブロックに与える引数を表しています。

が、この PARAMETERS、どういう文字列を渡しても受け取る事ができません。

(defun my-org-special-block (special-block contents info)
  "Sample code."
  (let ((params (org-element-property special-block :parameters))) ;; そんな物はないのでnil
    (if params
        (my-org-parse-params params)
      contents)))

3 行目で PARAMETERS の値を取得しようとしていますが、常に nil となり、取得できません。キーが誤っているのではないかとも思われますが、そもそも PARAMETERS が special-block に含まれていません。これは special-block をパースするソースコードからわかります。special-block をパースするコードは、org-element.el の org-element-special-block-parser です。この関数は最終的に special-block のメタデータを以下のように構築して返します。

(list 'special-block
      (nconc
       (list :type type
             :begin begin
             :end end
             :contents-begin contents-begin
             :contents-end contents-end
             :post-blank (count-lines pos-before-blank end)
             :post-affiliated post-affiliated)
       (cdr affiliated)))

この中に PARAMETERS に関する物が存在していない事がわかります。そのため、独自の special-block を構築する際、同一の NAME を使いつつ PARAMETERS で内容を分岐させたり情報を付け加えたりはできません。

もし、そのような事をしたい場合は NAME に全ての情報を含めつつ、バックエンド構築時に special-block を処理する関数内で NAME (:type キーを用いて取得できます) を見て判断するようにしましょう。