2020-12-19 ,

個別のorg-modeファイルにエクスポート時のフィルターを設定する

Defining filters for individual files(個別のファイルにフィルタを定義する)に書かれている例を試してみました。

#+BIND: org-export-filter-timestamp-functions (tmp-f-timestamp)
#+BIND: org-export-filter-strike-through-functions (tmp-f-strike-through)
#+BEGIN_SRC emacs-lisp :exports results :results none
  (defun tmp-f-timestamp (s backend info)
    (replace-regexp-in-string "&[lg]t;\\|[][]" "" s))
  (defun tmp-f-strike-through (s backend info) "")
#+END_SRC

time stamp [2020-12-19 Sat 14:06]

abc +def+ ghi

この例では二つのフィルタ関数を作成しています。一つはタイムスタンプのブラケット([]や<>)を消去する tmp-f-timestamp 関数、もう一つは取り消し線のテキストをまるまる消去する tmp-f-strike-through 関数です。一般的にフィルタ関数は、引数sの文字列(バックエンドによって変換済みの文字列)を再加工して返すことになっています。

この二つの関数をソースブロック( #+BEGIN_SRC emacs-lisp#+END_SRC )内に書くことでエクスポートするたびに評価させ関数を定義しています。ヘッダーオプション :exports results :results: none の指定によって、エクスポートするたびに毎回評価させつつ実際には何も(リスティングや結果等を)エクスポートしないようにしています。

さらに #+BIND: でそれらの関数を変数 org-export-filter-timestamp-functionsorg-export-filter-strike-through-functions に設定しています。

これであとはエクスポートすれば time stamp [2020-12-19 Sat 14:06][] が削除され、 abc +def+ ghi の部分が abc ghi になるはず……

あれれ、HTMLでエクスポートしてみましたがフィルタが適用されていません。

ソースブロック(#+BEGIN_SRC#+END_SRC)の部分はエクスポート時にyes/noの確認がありyesを選択しました。 tmp-f-timestamptmp-f-strike-through はちゃんとEmacs内に登録されているので評価されていることは間違いありません(エクスポートが終わっても tmp- で始まる関数が残っているのは不愉快ではありますが)。

変数 org-export-filter-timestamp-functionsorg-export-filter-strike-through-functionsnil 。となるとBIND( #+BIND: )の部分が機能していない? しかし調べたところ #+BIND: はエクスポートの間だけバッファローカル変数になると書かれています。なら今nilでも当然ですが……ははぁ、これはセキュリティがらみですね。BIND部分を無条件で評価してしまうと他人から貰ったorg文書をエクスポートしたときにイタズラされる可能性があります。

探してみると org-export-allow-bind-keywords という変数があって nil になっていました。試しにバッファ内で M-: (setq-local org-export-allow-bind-keywords t) してみたらちゃんとフィルタが機能しました。

うーんしかし org-export-allow-bind-keywords を常に t にするのは少々不安ですし、どうするべきなんでしょう。

試しに (setq-local org-export-allow-bind-keywords t) をソースブロックの中に入れてみました。

#+BIND: org-export-filter-timestamp-functions (tmp-f-timestamp)
#+BIND: org-export-filter-strike-through-functions (tmp-f-strike-through)
#+BEGIN_SRC emacs-lisp :exports results :results none

  ;;; 追加!!!
  (setq-local org-export-allow-bind-keywords t)

  (defun tmp-f-timestamp (s backend info)
    (replace-regexp-in-string "&[lg]t;\\|[][]" "" s))
  (defun tmp-f-strike-through (s backend info) "")
#+END_SRC

time stamp [2020-12-19 Sat 14:06]

abc +def+ ghi

ファイルを開き直してエクスポート(ソースブロックの評価はyes/no確認あり)してみるとちゃんとフィルタが機能してブラケットや取り消し線部分が消去されていました。つまりBINDとソースブロックを評価するセキュリティリスクがソースブロックに一本化されたわけです。どうなんだろうこれ。

最初からBINDなんか使わなければいいんじゃないでしょうか。

#+BEGIN_SRC emacs-lisp :exports results :results none
  (setq-local org-export-filter-timestamp-functions '(tmp-f-timestamp))
  (setq-local org-export-filter-strike-through-functions '(tmp-f-strike-through))

  (defun tmp-f-timestamp (s backend info)
    (replace-regexp-in-string "&[lg]t;\\|[][]" "" s))
  (defun tmp-f-strike-through (s backend info) "")
#+END_SRC

time stamp [2020-12-19 Sat 14:06]

abc +def+ ghi

うん、これでもちゃんとフィルタされます。

逆にBINDだけにするなら次のようにすれば良いでしょう。

#+BIND: org-export-filter-timestamp-functions ((lambda (s backend info) (replace-regexp-in-string "&[lg]t;\\|[][]" "" s)))
#+BIND: org-export-filter-strike-through-functions ((lambda (s backend info) ""))

time stamp [2020-12-19 Sat 14:06]

abc +def+ ghi

この場合 org-export-allow-bind-keywords 変数が t ならフィルタされ nil ならされません。 org-confirm-babel-evaluate 変数のようにBINDを評価するときにyes/no確認が出せれば良いのかもしれないが、そういう設定は見当たりません。まぁ、そこまでするならソースブロックで良いでしょう。

ちなみにソースブロックを使う方法で tmp-* 関数が残ってしまうのが気に入らなければ次のようにlambdaにしてしまえば良いのでしょうきっと。

#+BEGIN_SRC emacs-lisp :exports results :results none
(setq-local org-export-filter-timestamp-functions
            (list (lambda (s backend info)
                    (replace-regexp-in-string "&[lg]t;\\|[][]" "" s))))
(setq-local org-export-filter-strike-through-functions
            (list (lambda (s backend info)
                    "")))
#+END_SRC

time stamp [2020-12-19 Sat 14:06]

abc +def+ ghi

評価するかいちいち確認するのが嫌ならば(かつ org-confirm-babel-evaluatenil にするのが嫌ならば)、あらかじめ何らかの条件で自動的にフィルタが設定されるようにどこかに仕込んでおくことになりそうです。

Pingback / Trackback