Tag Archives: Emacs

2019-05-01

Emacs + Gnusでメールを読み書きする設定(Gmail、IMAP、POP複数アカウント)

普段Wanderlustを使っているのですが久しぶりにGnusに再挑戦、メールの読み書きが出来るようにしてみました。

環境

GNU Emacs 26.1.92 (build 1, x86_64-w64-mingw32)
 of 2019-03-08
Gnus v5.13

Gnus関連ファイルをひとつのディレクトリにまとめる

デフォルトだと ~/ の下にいろんなファイルを勝手に作るのでそれを ~/gnus/ に変更しました。 既に使っているWanderlustと併用したいので ~/Mail/ は特に困ります。

Gnus用設定ファイルも ~/gnus/.gnus.el に移したいのですが、これは .emacs や init.el の方に書かないとダメですね。その他の設定は .gnus.el に書くことにします。

  1. .emacs や init.el に (setq gnus-home-directory "~/gnus") を書く
  2. 次のコードを ~/gnus/.gnus.el に書く
;; Move home directory to ~/gnus
;; Write (setq gnus-home-directory "~/gnus") on init.el
(setq message-directory "~/gnus/Mail"
      mail-source-directory "~/gnus/Mail"
      nnfolder-directory "~/gnus/Mail/archive"
      pop3-uidl-file "~/gnus/.pop3-uidl"
      nntp-authinfo-file "~/gnus/.authinfo"
      auth-sources '("~/gnus/.authinfo" "~/gnus/.authinfo.gpg" "~/gnus/.netrc"))

受信設定

設定したメールアカウントは次の4つです。

  • Gmail
  • IMAPで扱う独自のアカウント
  • POPで扱う独自のアカウント(二つ)
;;; ~/gnus/.gnus.el

(require 'nnir)

;; Make Gnus NOT ignore [Gmail] mailboxes
;; Gmailのメールボックス名を無視しないようにする。
;; デフォルトの正規表現だと[Gmail]という名前にマッチしてしまうので。
(setq gnus-ignored-newsgroups "^to\\.\\|^[0-9. ]+\\( \\|$\\)\\|^[\"]\"[#'()]")

;; Use gnus-secondary-select-methods only
;; gnus-select-method は使わず gnus-secondary-select-methods のみを使う。
;; リストだけ使う方が追加・廃止が楽なので。
(setq gnus-select-method '(nnnil))

;; Gmail (IMAP)
(add-to-list
 'gnus-secondary-select-methods
 '(nnimap "gmail"
          (nnimap-address "imap.gmail.com")
          (nnimap-server-port 993)
          (nnimap-stream ssl)
          ;; Search
          (nnir-search-engine imap)))

;; My Email 1 (IMAP)
(add-to-list
 'gnus-secondary-select-methods
 '(nnimap "myaccount1"
          (nnimap-address "myimapserver1.example.jp")
          (nnimap-server-port 993)
          (nnimap-stream ssl)
          ;; Search
          (nnir-search-engine imap)))

;; WanderlustのMH形式フォルダを読み込む。が、起動時に毎回時間がかかるのでコメントアウト。
;; ;; My Old Email Archive (Wanderlust's MH Folders)
;; (add-to-list
;;  'gnus-secondary-select-methods
;;  '(nnmh ""
;;         (nnmh-directory "~/Mail")
;;         (nnmh-get-new-mail nil)))

;; 手元にダウンロードしてくるタイプのPOP、IMAPアカウント。
;; My Email 2,3 (POP)
(add-to-list
 'gnus-secondary-select-methods
 '(nnml ""))

(setq mail-sources
      '((pop :server "mypopserver2.example.jp"
             :port 995
             :user "mypopuser2"
;;             :password "???" ;;=> .authinfo に machine mypopserver2.example.jp login mypopuser2 port 995 password ??? と書いた方が良い。ミニバッファにパスワードを入力しても、POPの場合はなぜか自動で保存してくれないので手動で書き込んだ方が良い。
             :authentication apop
             :stream ssl
             :leave t ;; or N days
             )
        (pop :server "mypopserver3.example.jp"
             :port 995
             :user "mypopuser3"
;;             :password "???"
             :authentication apop
             :stream ssl
             :leave t
             )))

;; ソースによってグループを分ける。
(setq nnmail-split-methods
      '(("myaccount2" "^X-Gnus-Mail-Source: pop:mypopuser2@mypopserver2\\.example\\.jp$")
        ("myaccount3" "^X-Gnus-Mail-Source: pop:mypopuser3@mypopserver3\\.example\\.jp$")
        ("unknown-source" "")))

Gnusでは情報源は gnus-select-methodgnus-secondary-select-methods に設定します。 なぜか同じような機能のものが二つあるのですが、おそらく最初は gnus-select-method だけがあって、後から複数の情報源を設定出来る gnus-secondary-select-methods を追加したのではないでしょうか? 今回はリストで複数設定出来る gnus-secondary-select-methods のみを使います。 gnus-select-method には nnnil を設定して無効化しました。ネットニュースを読むならニュースサーバをここに設定しても良いと思います。

nnimap で指定したIMAPサーバ上のメッセージは、手元にファイルをダウンロードすることなく読むことが出来ます。

nnmlmail-sources で指定したPOPサーバ上のメッセージは、 ~/gnus/Mail/ (デフォルトだと~/Mail/)にダウンロードしてから読むことになります。

mail-sources に複数のアカウントを指定した場合、全アカウントのメールが全て一箇所にまとめられてしまうようでした。なので nnmail-split-methods で振り分けの設定をしています。幸い X-Gnus-Mail-Source というヘッダーがついていたのでそれで振り分けられました。何かもう少しうまい仕組みがあれば良いのですが……。グループパラメータの mail-source が使えるかなとも思ったのですがそちらは試していません。

POPでメールをサーバに残すには :leave t を指定します。これが無いと受信したメールはサーバから削除してしまうので注意してください。整数で日数を指定することも出来るようです。

POPのパスワードは .authinfo(や.authinfo.gpg)にあらかじめ書いておくことをおすすめします。どこにも書かなければアクセス時にミニバッファで聞かれますが、自動的に .authinfo に保存してくれませんでした。 nnimap の場合は保存してくれたのですが。

IMAP(nnimap)のパスワードも .authinfo に保存します。あらかじめ書かなくてもミニバッファで聞かれたときに入力すれば自動的に保存されました(むしろ下手に書いて形式に間違いがあってハマりました)。

Gmailで二段階認証している場合等はアプリパスワードを発行する必要があると思います。

送信設定

複数のアカウントがあるので送信設定も適切に切り替える必要があります。

何を切り替えるべきか:

  • (Fromの)名前
  • (Fromの)メールアドレス
  • 文末の署名
  • 送信したメールをどこに保存するか(Bcc, Gcc)
  • SMTPサーバとの接続情報

切り替える条件案:

  • Fromヘッダー
  • メール作成時のグループ

探してみるとFromによってSMTPを切り替える設定(Multiple SMTPAccounts – Emacs Wiki)を見つけたのですが、色々試してみて最終的に gnus-posting-styles でメール作成時のグループにより適切なヘッダーを設定する方法で落ち着きました。

;;; ~/gnus/.gnus.el

;; デフォルト送信設定
(setq smtpmail-stream-type 'starttls) ;;基本的に全てstarttlsで送る。
(setq smtpmail-smtp-server "mysmtpserver2.example.jp"
      smtpmail-smtp-service 587
      smtpmail-smtp-user "mysmtpuser2") ;;デフォルトのSMTPサーバ
(setq user-full-name "My FullName"
      user-mail-address "myaccount2@example.jp") ;;デフォルトの名前とメールアドレス

;; メール作成時に作用する設定
(setq gnus-posting-styles
      '(
        ;; IMAP
        ("^nnimap\\+gmail:"
         (name "My FullNameG")
         (address "myaccountg@gmail.com")
         (signature "My FullNameG\nmyaccountg@gmail.com")
         (gcc "nnimap+gmail:Sent")
         ("X-Message-SMTP-Method" "smtp smtp.gmail.com 587 myaccountg@gmail.com"))

        ("^nnimap\\+myaccount1:"
         (name "My FullName1")
         (address "myaccount1@example.jp")
         (gcc "nnimap+myaccount1:INBOX")
         ("X-Message-SMTP-Method" "smtp mysmtpserver1.example.jp 587 mysmtpuser1"))

        ;; POP
        ("^nnml:myaccount2\\(\\..*\\)?$"
         (name "My FullName2")
         (address "myaccount2@example.jp")
         ("Bcc" "myaccount2@example.jp")
         ("X-Message-SMTP-Method" "smtp mysmtpserver2.example.jp 587 mysmtpuser2"))

        ("^nnml:myaccount3\\(\\..*\\)?$"
         (name "My FullName3")
         (address "myaccount3@example.jp")
         ("Bcc" "myaccount3@example.jp")
         (signature "** My FullName3 **")
         ("X-Message-SMTP-Method" "smtp mysmtpserver3.example.jp 587 mysmtpuser3"))
        ))

gnus-posting-styles変数を使用すると様々な条件でメールヘッダーや署名等を切り替えることが出来ます。この変数はメール作成を開始する時点で作用するので、本文を書くときに効果を目で確認出来ます。

上の設定ではメール作成時のグループ名を元に、名前、メールアドレス、署名、送信済みメールの送り先、使用するSMTPサーバを切り替えています。

送信したメールの保存先は、私の場合次のようにしました。

  • POPアカウントならBccで自分自身にコピーを送る
  • IMAPアカウントならGccを送信済みフォルダーに設定する

POPでBccしているのは他のPCからでも見られるようにするためですが、それが不要ならばGccをnnml:myaccount2とかにしてローカルに保存するだけでも良さそうです。

X-Message-SMTP-Method というヘッダーを使用すると送信時に使用するSMTPサーバ(ポート、ユーザ名)を指定出来ます。このヘッダーは送信時に削除されて相手には届きませんでした(試した限り)。 この方法だとSSL/TLS暗号化の方式を個別に指定出来ないような気がしますが、私の場合は全てSTARTTLSで問題ありませんでした。デフォルトの設定では、使えるならSTARTTLS、使えなければ暗号なしになるみたいです。

見た目の設定

;;; ~/gnus/.gnus.el

;; Tree view for groups.
;; デフォルトをトピックモードとする。
;; https://www.gnu.org/software/emacs/manual/html_node/gnus/Group-Topics.html
(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)

;; Referencesヘッダーを元にスレッドを構築する。同じSubjectというだけでスレッドになると困るので。
;; gather threads by References headers (default is by subject)
(setq gnus-summary-thread-gathering-function 'gnus-gather-threads-by-references)

;; Summary Line Format
;; 短い年月日日時(190503T1234)、短いFrom、記事行数不要
(setq gnus-summary-line-format "%U%R%z %&user-date; %I%(%[%-15,15f%]%) %s\n"
      gnus-user-date-format-alist '((t . "%y%m%dT%H%M")))

GnusかWanderlustか

ここまでやってみましたが、結局私は当面Wanderlustを使うと思います。

手元の環境(Windows+自分でビルドしたEmacs)だと数回に一回は送受信時にエラーが発生します。これはGnusでもWanderlustでも起きるのですが未だに原因がつかめていません(SSLでも平文でも起こるのでgnutlsがらみでも無さそう?)。 今回Gnusを試してみたのはこれが解決するかもしれないと思ったのが一番の理由なのですが残念ながら変わりませんでした。

メールソフトとしての使い勝手はWanderlustの方が普通だと思います。カスタマイズを進めていけばGnusでもそれほど悪くないのかもしれませんけれど、デフォルトの状態があまりにも。

Wanderlustはバグが多くそれが一向に解決される気配が無いのも今回Gnusを試した理由の一つなのですが、まぁ、Wanderlustでも一応最低限は使えていますので。

添付ファイルまわりとか日本語まわりとかはまだ試していないので分かりません。Wanderlustだとおかしな挙動をすることが良くあるので、それがGnusで問題なければ良いのですが。

2018-12-21

Emacs Helmの色を修正する

anythingからhelmへ移行しましたがどうにも違和感が残っています。うーん、配色が悪い。全体的に色がガチャガチャしすぎなんですよね。背景色を指定しすぎている気がします。

プロンプトのカーソル色が黒くなってしまう問題があったのですが、それはこちらのIMEの設定のせいでした。IMEをONにしたら色を変えてOFFにしたら戻すようにしていたのですが、戻すときに黒にしていました。なぜか普段は白に戻ってくれるのですが、背景が黒なので自動的に白にしてくれているのでしょうか……。

それはともかく、気に入らないところをM-x describe-faceやM-x customize-faceで修正。

  • ディレクトリの色(helm-ff-directory)がなんで白背景に赤文字?? フレームの背景色が白であることが前提なのでしょうか? とにかくこれでは見づらいのでdired-directoryと同じ色にしました。一貫性があってすぐにディレクトリと分かります。
  • .や..の色(helm-ff-dotted-directory)が灰色背景に黒文字。み、見づらすぎ……。dotted directoryって.emacs.dとかには適用されていませんね。 . と .. だけみたいです。diredだと . と .. 以外のドットファイルはグレーにしているのですが、helmにはそういうfaceは無いようです。.と..だけを別の色にする必要性を感じなかったのでhelm-ff-directoryと同じ色にしてしまいました。
  • マークの色(helm-visible-mark)がド派手な緑……。これもdiredのマーク色で……と思ったけれどしっくりきません。regionと同じ単純な青色で。文字をboldにすればカーソルと被ってもマークされていると分かります。
  • カーソルの色(helm-selection)も濃い緑……。白じゃダメなの? うーん、さすがに明るすぎますか。文字も見づらい。regionより少し明るい青で。
  • バッファリストにも白背景に赤文字のディレクトリ色(helm-buffer-directory)がありました。ディレクトリのfaceいくつあるの? ff bookmark bufferとありますね。

これだけで少しは落ち着いた色になった気がします。

2018-12-21

Windows上のEmacsでhelm-locateを使う(Windows Searchで)

helm-locateはWindowsではes.exe(Everything)を使うようになっています。

しかしWindowsでは標準でWindows Searchという検索エンジンが入っています。これが使えればわざわざ機能が被る別アプリ(サービス)を入れる必要は無くなります。Windows Searchは重いというのでOFFにしている人もいると思いますが一応標準で入っているものですし一時的にインデックスを停止することも出来るのでそれほど嫌がるものでもないと思います。

先日、helmからWindows Searchでファイル検索できるhelm-windows-searchを作成したのですが、helm-locateはhelm-find-filesから呼び出せるようになっている(C-x C-fで開いた後もう一回C-x C-fで開く)のでhelm-locate自体もEverythingではなくWindows Searchで動くようになっていれば便利そうだなと思いました。

方針としては、Emacs Lispとadoquery.exeで可能な限りlocateコマンドをエミュレートすることにします。

helm-locateでlocateコマンド(またはes.exe)を起動しているのはhelm-locate-init関数です。 この関数はコマンドラインの作成とプロセスの起動をまとめて行っています。 コマンドラインの作成部分だけ差し替えることは出来ないので、関数を丸丸置き換えることにします。

というわけで、先日のHelm Windows Searchhelm-locate-windows-search.elを追加しました。これをロードパスの通ったところに置き、adoquery.exeを同じディレクトリかまたはパスが通ったところに置き、次の設定をするとhelm-locate-initが置き換わります。

(autoload 'helm-locate-windows-search-setup "helm-locate-windows-search")
(with-eval-after-load "helm-locate" (helm-locate-windows-search-setup))

<helm prefix> l やC-x C-f C-x C-f でhelm-locateが開き、そこでWindows Searchを使った検索が出来ます。ただしlocateをエミュレートしているため、Windows Searchの複雑なクエリは書けません。 -bオプションでファイル名だけのマッチが出来るくらいでしょうか。

別にlocateコマンドにこだわる必要も無さそうなのでhelm-locate全体をhelm-windows-searchで置き換えてしまっても良いかもしれません。その場合は次のようにしてhelm-locate-1関数をhelm-windows-search-1関数へ置き換えてしまえばOKです。

(with-eval-after-load "helm-locate"
  (fset 'helm-locate-1
        (lambda (&optional localdb init from-ff default)
          (require 'helm-windows-search)
          (helm-windows-search-1 init default)))

locateコマンドではローカルDBが使えますがWindows Search(やEverything)ではできません。その代わりWindows Searchでは検索するディレクトリを限定する機能(SCOPEやDIRECTORY)があるのでうまく使いたいところですがどうにもうまくハマらなかったので実現出来ていません。

2018-12-20

Emacs Helm から Windows Search を使う

HelmからWindows Search(Windowsデスクトップサーチ)を利用するelisp helm-windows-search.elを作りました。

(日本語が通らない場合はfakecygptyなどstart-processをフックしている設定が無いか確認してください)

最近ようやくAnything.elからHelmへ移行したのですが、設定を見直しているときにWindows Searchするコードを見つけてそういえばそんなものを作ったなぁと思い出したのでした。

要するに使っていなかったのですが、色々調べていくうちにもう少し使いやすく出来そうだなと思ったので手を加えてみました。

exe部分は汎用的なADOアクセスラッパーになっていて、elispの方からSQLクエリを作成するので後から色々融通が利きます。

とりあえず次のようなクエリを書けるようにしてみました。

  • apple banana orange
  • “you’re looking for”
  • author:misohena
  • title:hello\ world
  • size:>1000000000
  • date:2017-10-20..2018-3
  • kind:folder hogeprojectdir
  • kind:music hogehoge
  • ext:mp3
  • filename:happy.txt
  • contents:brabrabra
2018-10-12 ,

Org2blogでアイキャッチ画像を設定する

Org2blogでアイキャッチ画像(投稿サムネイル, featured image, post thumbnail)を指定するオプションを追加しました。次のように書けます。

#+TITLE: Org2blogでアイキャッチ画像を設定する
#+POST_THUMBNAIL: ./some-featured-image.jpg

https://github.com/misohena/org2blog/commit/ffbb7146f3a571db7841aac89f41bb3e93c578ca https://github.com/misohena/org2blog/commit/f3e9385d11d1d6711033da71bf31e4e58cd8ea53 (2019-03-20最新版に追従)

ファイル名が変わっていたらアップロードして再設定します。オプションを空文字列にすればアイキャッチ画像は投稿から取り外されます。ただし、APIからメディアを削除する方法が分からなかったので変わる前の画像はメディアライブラリに残り続けますのでご注意を。

ソースコード全体としては https://github.com/misohena/org2blog の image-fix ブランチで提供しています。

2018-10-11 ,

Org2blogでサムネイル画像のサイズをリンク毎に個別に設定する

このBlogは Org2blog + WordPress で書かれているわけなんですが、画像を張るときにちょっと気になることがあります。

それは画像のサイズを個別に指定する標準的な方法が無いこと。 org2blog/wp-image-thumbnailsorg2blog/wp-image-thumbnail-size という設定があってそれを使えば全体でサイズを指定出来るのですが、一つの文書の中でこの画像はどうでもいいので小さくしたい、この画像は重要なので大きくしたい、といった個別に指定する方法が用意されていません。

最終的にHTMLでエクスポートされるので、画像(img要素)に対してstyleやwidth属性を設定すれば無理矢理大きさを変えられます。

#+ATTR_HTML: :width 240px
[[file:./a.png]]

しかしこの場合、あくまで表示時に縮小することになるため不必要に大きな画像をダウンロードすることになります。WordPress側ではアップロード時にいくつかの解像度差分を自動的に生成してくれているのに勿体ない話です。

というわけで、作ったのが次のパッチ。

https://github.com/misohena/org2blog/commit/244fdc04ec0d470ce4434c21b4c6476840d25632 https://github.com/misohena/org2blog/commit/5adca9e1215cf2d0c7738e86444c95817b1ad855 (2019-03-20最新版に追従)

imgのwidth=を見て適切なサイズの画像を選ぶようにしてみました。

ただ、実はこれだけでは不十分で、同じ画像をサイズを変えて何度も使いたい場合にうまくいきません。org2blogは内部で一つのファイル名に対して一つのサムネイルサイズを前提にしているため、最初に指定した画像リンクのサイズが以降使われてしまいます。

それを解決してみたのが次のパッチ(一つ目のパッチを前提にしています)。

https://github.com/misohena/org2blog/commit/fb74f87429883ed04aa00781e4e21c8e4a873ded https://github.com/misohena/org2blog/commit/38eef7a290bef8b6d2195cdd4a21df9182f77040 (2019-03-20最新版に追従)

これによって同じ文書の中であっても次のような指定が可能になります。

# mediumサイズが使われる
#+ATTR_HTML: :width 200px
[[file:./a.png]]

# largeサイズが使われる
#+ATTR_HTML: :width 640px
[[file:./a.png]]

# org2blog/wp-image-thumbnail-sizeで指定したサイズが使われる
[[file:./a.png]]

ソースコード全体としては https://github.com/misohena/org2blog の image-fix ブランチで提供しています。

2017-12-21

org-mode スプレッドシート(表計算)での参照の書き方まとめ

org-modeで表計算が出来るということはよくご存じかと思いますが、細かいところがよく分からないという方も多いのではないでしょうか。特にフィールド(いわゆるセル)を式内から参照する書き方は広く使われている表計算ソフトとは異なるのでなかなか覚えられない、普段使うところだけ覚えてるということも多いと思います。なので今回はorg-modeのスプレッドシート機能の内、「参照」に的を絞ってまとめてみました。

参考: Org Mode マニュアル 3.5.1 参照

表内のフィールドや範囲等を参照する方法

フィールド参照

意味
@0 現在の行
$0 現在の列
@1 1行目
$2 2列目
@1$2 1行目2列目
@-1 直上の行
$-1 左隣の列
@-1$+3 現在のフィールドから上に1行、右に3列
@< 最初の行
@> 最後の行
$< 最初の列
$> 最後の列
@>$2 最終行の2列目
@>$> 最終行の最終列(右下)
@<<< 最初の行から下へ数えて3行目(@3)
@>> 最後の行から上へ数えて2行目
$<< 最初の列から右へ数えて2列目($2)
$>>> 最後の列から左へ数えて3列目
@I 一つ目の水平線
@-I 現在の行から上にある最初の水平線
@+II 現在の行から下にある2番目の水平線
@III+2 三つ目の水平線から下にある二番目の行
@III-1 三つ目の水平線の直上の行
  • @行$列
  • 符号が付くと相対指定
  • <が先頭で>が末尾
  • @Iは水平線
  • < > I は複数連続で書くとその個数分だけズレる

範囲参照

意味
@2$3..@3$5 「2行目の3列目」から「3行目の5列目」までの矩形範囲(6フィールド)
@2$1..@>>$> 「2行目の1列目」から「下から2行目の右端列」までの矩形範囲
@I..@II 一つ目の水平線から二つ目の水平線までにある行、現在の列

始点.. 終点 の形で 始点 から 終点 までの 矩形範囲 を指す。 始点終点 はそれぞれフィールドへの参照。

式の右辺に書いた場合範囲内の値を含む ベクトル になる。(例えば @1$1..@2$2 なら4要素のベクトルになる)

式の左辺に書いた場合計算で書き換える対象を表す。(@1=1行目の全列の式, $1=1列目の全行の式, @1$1..@2$2=左上2x2(4マス)の式)

※式の 左辺 に範囲参照を書く時 始点 には水平線参照(@I 等)は書けない(ダメな例: @I+1$>..@II-1$>=foo)。 終点 にはなぜか書ける(書ける例: @2$>..@II-1$>=foo)。(参考: 水平線参照を左辺には書けないのはなぜ?)

名前参照

意味
$name nameという名前の何かを参照

参照できる物:

  • 連想リスト org-table-formula-constants
  • #+CONSTANTS: name = value (←この行の上でC-c C-cしておくこと)
  • org文書内のプロパティ(ex:$PROP_プロパティ名)
  • constants.elの定数
  • 列名、フィールド名、パラメータ (参考: Org Mode マニュアル 3.5.8 一歩進んだ機能)

リモート参照

意味
remote(table1, @>$>) table1という名前の表の最終行最終列(右下)にあるフィールドを参照。

#+NAME: 名前 を表の直前に書くとその表を名前で参照できる。

フィールド座標

意味
@# 現在の(計算対象の)行番号に展開される
$# 現在の(計算対象の)列番号に展開される
@@# @ ( @# ) と解釈。つまり@現在の行番号
$$# $ ( $# ) と解釈。つまり$現在の列番号
@$# @ ( $# ) と解釈。つまり@現在の列番号
$@# $ ( @# ) と解釈。つまり$現在の行番号

例1:列名と範囲参照

#+NAME: purchase2016
|   | 品名   | 単価 |   個数 |    計 |
| ! | item   | unit | amount | total |
|---+--------+------+--------+-------|
| # | りんご |  128 |      5 |   640 |
| # | みかん |  200 |      3 |   600 |
|---+--------+------+--------+-------|
| # |        |      |        |  1240 |
#+TBLFM: @3$>..@II$>=$unit*$amount::@>$>=vsum(@I..@II)

! の行は列名となる。列名は $unit*$amount のように使える。 $3*$4 より幾分分かりやすい。 # の行は自動再計算(フィールド入力後TABやRETで全体を再計算する)対象となる。その他にも同じような方法でフィールド名やパラメータを定義する機能がある。(参考: Org Mode マニュアル 3.5.8 一歩進んだ機能)

@3$>..@II$>=$unit*$amount

式の左辺にある @3$>..@II$> は「3行目の最後の列」から「2本目の水平線までの行の最後の列」までの範囲を表す。つまり右端の小計を入れる部分(右下の合計部分を除く)を指す。水平線参照だけを使って @I$>..@II$> のようには(左辺には)書けない(エラー:”Can’t assign to hline relative reference”)。列名を使って @3$total..@II$total のようにも書けなかった。 @<<<$>..@>>$> のようには書ける。

@>$>=vsum(@I..@II)

@I..@II は現在の列の一つ目の水平線から二つ目の水平線の間の範囲を表す。範囲内の値を要素とするベクトルが作られ、vsumでその合計が計算される。結果は @>$> つまり一番右下のフィールドに格納する。

今回は代入先の範囲が重ならないように厳密に指定して書いたが、 #+TBLFM: $>=$unit*$amount::@>$>=vsum(@I..@II) のように書いても構わない。 $> は右端の全てのフィールド(ヘッダー以外)を意味するので右下( @>$> )と重なってしまうように見えるが、列指定よりフィールド指定が優先されることが決まっている。(参考: Org Mode マニュアル 3.5.5 列の数式)

例2:リモート参照

| 税抜き | 税率 | 税込み |
|--------+------+--------|
|   1240 | 1.05 |   1302 |
|   1240 | 1.08 |   1339 |
#+TBLFM: $1=remote(purchase2016,@>$>)::$3=floor($1*$2)

remote(表名, 参照) で別表の値を取り出せる。

この例ではpurchase2016という名前の表(例1)の一番右下のフィールド(@>$>)を1列目($1)へ代入している。

例3: リモート参照(表の名前を計算時に決める)

purchase2016とpurchase2017の二つの表があるとき、この二つの表の合計部分(一番右下のフィールド)を別の表から参照したいとする。

#+NAME: purchase2016
|   | 品名   | 単価 |   個数 |    計 |
| ! | item   | unit | amount | total |
|---+--------+------+--------+-------|
| # | りんご |  128 |      5 |   640 |
| # | みかん |  200 |      3 |   600 |
|---+--------+------+--------+-------|
| # |        |      |        |  1240 |
#+TBLFM: @3$>..@II$>=$unit*$amount::@>$>=vsum(@I..@II)

#+NAME: purchase2017
|   | 品名   | 単価 |   個数 |    計 |
| ! | item   | unit | amount | total |
|---+--------+------+--------+-------|
| # | りんご |  128 |      3 |   384 |
| # | みかん |  200 |      8 |  1600 |
|---+--------+------+--------+-------|
|   |        |      |        |  1984 |
#+TBLFM: @3$>..@II$>=$unit*$amount::@5$5=vsum(@I..II)

列に表名を入れれば次のように書ける。

|   表名       | 金額 |
|--------------+------|
| purchase2016 | 1240 |
| purchase2017 | 1984 |
#+TBLFM: @<<$>..@>$>=remote($1,@>$>)

remoteの第一引数である $1 は先に展開されるのに対して第二引数である @>$> は展開されない(1984に置き換わらない)のが興味深い。

表名を表の中に書くのはかっこ悪いので年から表名文字列を生成してリモート参照したいなら次のようにする。

|   年 | 金額 |
|------+------|
| 2016 | 1240 |
| 2017 | 1984 |
#+TBLFM: @<<$>..@>$>='(org-table-get-remote-range (concat "purchase" $1) (string ?@ ?> ?$ ?>))

remote(表名, 参照) の書き方では文字列の結合等はできない(リモート参照の展開タイミング的に)ので、Elisp式を使っている。

(string ?@ ?> ?$ ?>) の部分は "@>$>" とは書けない。展開のタイミング的に。

(参考: emacs – Org mode spreadsheet programmatic remote references – Stack Overflow)

例4: 結果の行内への埋め込み

行内コードブロックを使えば表の中の値を文書中の行内に埋め込める。

#+NAME: ex4
| 品名   | 金額 |
|--------+------|
| りんご |  123 |
| みかん |   89 |
|--------+------|
|        |  212 |
#+TBLFM: @>$>=vsum(@I..@II)

合計は src_emacs-lisp[:results raw]{(org-table-get-remote-range "ex4" "@>$>")} 円です。

参考: Org Mode: Using table formula outside of a table? – Emacs Stack Exchange

例5: 連番

| 番号 | 番号4桁 |
|------+---------|
|    0 |    0000 |
|    1 |    0001 |
|    2 |    0002 |
|    3 |    0003 |
#+TBLFM: $1=@#-2::$2='(format "%04d" (- @# 2))

例6: 文字列の参照

基本的にElisp式で行った方が良い。Calcで扱えないこともないが非ASCIIは怪しい?

| 参照する文字列→      | abc                  | りんご                                |
| ↓式                  | ↓結果               | ↓結果                                |
|-----------------------+----------------------+---------------------------------------|
| @1                    | abc                  | #ERROR                                |
| "@1"                  | [40, 97, 98, 99, 41] | [40, 12426, 12435, 12372, 41]         |
| string("@1")          | (abc)                | string([40, 12426, 12435, 12372, 41]) |
| '(identity @1)        | abc                  | りんご                                |
| '(format "%sです" @1) | abcです              | りんごです                            |
#+TBLFM: @3$2=@1::@3$3=@1::@4$2="@1"::@4$3="@1"::@5$2=string("@1")::@5$3=string("@1")::@6$2='(identity @1)::@6$3='(identity @1)::@7$2='(format "%sです" @1)::@7$3='(format "%sです" @1)::@8$2=string("$s1")

水平線(hline)参照の謎

水平線参照をフィールド参照として使うとどうなるか

単に @I と書いた場合どこを参照するのか。

|       | 10 |
|-------+----|
|       | 11 |
|       | 12 |
|-------+----|
| ↓式  |    |
| @I-1  | 10 |
| @I    | 11 |
| @I+0  | 11 |
| @I+1  | 11 |
| @I+2  | 12 |
| @II-1 | 12 |
#+TBLFM: @5$2=@I-1::@6$2=@I::@7$2=@I+0::@8$2=@I+1::@9$2=@I+2::@10$2=@II-1

水平線の直下の行を参照する模様。意図した動作かは不明。 @I+1 と書いた方が安心?

水平線参照を左辺には書けないのはなぜ?

範囲参照例1にも書いたが、水平線(hline)への参照(@I 等)は式の左辺に書けない。

例えば次の良くあるような例では、小計を集計するのに「一つ目の水平線から二つ目の水平線までの行、右端列」つまり @I$>..@II$> と左辺に書けると便利である。

|        | 重量 | 個数 | 計 |
|--------+------+------+----|
| みかん |   30 |    2 |    |
| りんご |   50 |    3 |    |
|--------+------+------+----|
|        |      |      |    |
#+TBLFM: @I$>..@II$>=$-2*$-1

しかし実際に書くとエラーになる。

Can't assign to hline relative reference

なぜ書けないのかメーリングリストを”left hline”で検索してみた。

長年未解決で放置中らしい。

リモート参照とフィールド座標の展開規則

例3でも触れたがremoteの第二引数は別表の参照前に展開されないように見える。

しかしマニュアルには次のような例がある。(Field coordinates in formulas)

@3 = 2 * remote(FOO, @1$$#)
Insert the doubled value of each column of row 1 of the table named FOO into row 3 of the current table.

この例の @1$$# はremote()を解決する前に @1$1 , @1$2 , @1$3 のように参照元の列の番号に展開されなければならないはずだ。

#+NAME: remote-ref-tbl1
| 1 |  2 |  3 |  4 |
| 5 |  6 |  7 |  8 |
| 9 | 10 | 11 | 12 |

| 2 | 4 | 6 |
#+TBLFM: @1=2*remote(remote-ref-tbl1, @1$$#)

ちなみに「現在の列」を表したいなら $0 やそもそも列を省略すれば良さそうだが、実際にやると次のようになる。

| 2 | 2 | 2 |
#+TBLFM: @1=2*remote(remote-ref-tbl1, @1$0)

マニュアルにもリモート参照の第二引数は絶対参照か名前参照でなければならないと書いてあるのでこの書き方はできないのだろう。

org-table-eval-formula 関数を見ると、 @# 等のフィールド座標表記はリモート参照よりも前に解決しているようだ。つまり、remoteとその引数の展開は次のような順番になっている。

  1. フィールド座標(@# $#)だけ先に解決(数字へ置き換え)
  2. 第一引数を現在の表上で解決し、得られた名前に従って参照先となる表を見つける
  3. 見つけた表上で1の結果得られた第二引数の参照を解決する

そもそもこの remote(表名, 参照) という表記は関数の計算などではなく文字列の置き換えに過ぎない。なので展開の規則はCalcともElispとも異なる。 実際マニュアルの例にもあるとおりElisp式内でも同じように書ける。

$2 = ‘(identity remote(FOO, @@#$1))
Copy text or values of each row of column 1 of the table named FOO into column 2 of the current table.
2017-10-29 ,

Windows版Emacs上でESSが文字化けする問題

勝手に default-process-coding-system 変えるなよ。

diff -u ess-20171022.322/lisp/ess-r-mode.el.old ess-20171022.322/lisp/ess-r-mode.el
--- ess-20171022.322/lisp/ess-r-mode.el.old     2017-10-29 01:06:34.182359100 +0900
+++ ess-20171022.322/lisp/ess-r-mode.el 2017-10-29 00:53:10.316792600 +0900
@@ -556,7 +556,8 @@
               (eq system-type 'cygwin))
       (setq use-dialog-box nil)
       (when ess-microsoft-p ;; default-process-coding-system would break UTF locales on Unix
-        (setq default-process-coding-system '(undecided-dos . undecided-dos))))
+        ;;(setq default-process-coding-system '(undecided-dos . undecided-dos))
+        ))
 
     (inferior-ess r-start-args cust-alist gdbp)
 

read.csvで入力した文字とバッファから入力した文字がどうしてもどちらか一方が化けてしまうので調べた。

Rがutf-8で入出力しているのかなと思って調べたら、Windows版はちゃんと現在のコードページで入出力してくれていた。 調べてみると process-coding-system のENCODING側がundecided-dosだから何事かと思ったら default-process-coding-system がRを起動した後だと書き換わっていた。 何でグローバルな設定である default-process-coding-system を勝手に書き換えちゃうかなー。

他にもWindows対応のコード(ess-microsoft-pで処理を分けているところ)は色々と変なところが多いね。

2017-10-26

org-modeのコードブロック(Babel)の使い方

基本構文

(公式マニュアル: Structure of code blocks – The Org Manual)

コードブロックは #+BEGIN_SRC で始まり #+END_SRC で終わる。 #+BEGIN_SRC の前に #+NAME:#+HEADER: が付く場合もある。

#+NAME: <name>
#+HEADER: <header>...
#+HEADER: <header>...
#+BEGIN_SRC <language> <switch>... <header>...
<body>
#+END_SRC

次の例ではmulという名前のemacs-lispのコードブロックを作成している。ヘッダー引数が二つ指定されている。

#+NAME: mul
#+BEGIN_SRC emacs-lisp :var x=2 :var y=3
(* x y)
#+END_SRC

名前が付いたコードブロックは他から参照できる。

関数のように呼び出すの例。C-c C-cしたりエクスポートしたりすると結果だけが出力される。
#+CALL: mul(x=5, y=6)

#+RESULTS:
: 30

↑CALLの上でC-c C-cするとRESULTSが生成される。

noweb参照の例。<<mul>>と書いた部分が置き換わる。
#+BEGIN_SRC emacs-lisp :noweb yes
(defun mul (x y)
  <<mul>>
)
#+END_SRC

CALLについてはコードブロックの呼び出し、noweb参照についてはnoweb参照を参照のこと。

行内でもコードブロックが書ける。

src_<language>{<body>}
src_<language>[<header>...]{<body>}

例:

2 * 3 の答えは src_emacs-lisp[:var x=2 :var y=3]{(* x y)}

2 * 3 の答えは 6

より具体的な例は言語毎の書き方を参照のこと。

コードブロックに関連するキー操作

(場所)キー操作 関数 動作
(コードブロック上で) C-c ‘ org-edit-src-code コードの編集。編集バッファから出るには再度C-c ‘を押す。 (公式マニュアル: Editing source code – The Org Manual)
(コードブロック上で) C-c C-c org-babel-execute-src-block コードを実行する。 (公式マニュアル: Evaluating code blocks – The Org Manual)
(orgファイル内で) C-c C-e org-export-dispatch エクスポートメニューを表示する。htmlでエクスポートしてブラウザで開くには続けてh oと打つ。エクスポート時に各コードブロックは評価される。

ヘッダー引数

(公式マニュアル: Header arguments – The Org Manual)

#+BEGIN_SRC <言語ID> の後には : で始まる引数が書け、様々なオプションが指定できる。

最も重要なのは :exports:results (最初のコロンと最後のsが抜けないように注意すること)。

:exports はコードブロックをエクスポートするときに何を出力するかを指定する。次のいずれかを指定できる。(公式マニュアル: exports – The Org Manual)

  • コードブロックのみを出力する(code)
  • 実行結果のみを出力する(results)
  • 両方を出力する(both)
  • 何も出力しない(none)

:exports の例:

#+NAME none-exports-example
#+BEGIN_SRC emacs-lisp :exports none :var x=0
(* x x) ;;このコードはエクスポートされない。他から名前で参照されるためのもの。
#+END_SRC

:results は実行結果をどのように扱うかを指定する(公式マニュアル: results – The Org Manual)。大きく分けて四種類の値を指定する。

  • どこから結果を得るか
    • 標準出力(output)
    • 言語が返した値(value)
  • 結果の種類(使用例は結果の受け取り方を参照のこと)
    • 表(table)
    • リスト(list)
    • 単一の値(scalar)
    • ファイルへのリンク(file)
  • 結果の出力形式
    • そのままOrg文書として出力(raw)
    • orgのコードブロック(#+BEGIN_SRC org)として出力(org)
    • htmlのエクスポートブロック(#+BEGIN_EXPORT html)として出力(html)
    • latexのエクスポートブロック(#+BEGIN_EXPORT latex)として出力(latex)
    • 同じ言語のエクスポートブロック(#+BEGIN_EXPORT 同じ言語)として出力(code)
    • pretty-printしたものを出力(一部の言語のみ対応)(pp)
    • :RESULTS::END: に挟まれた形で出力(drawer)
  • 結果をどう文書中に挿入するか(#+RESULTS:として)
    • 挿入しない(silent)
    • 置き換える(replace)
    • 最後に付け加える(append)
    • 最初に付け加える(prepend)

:results の例:

#+BEGIN_SRC emacs-lisp :results value raw drawer
"Hello\n\n| table | table |\n| table | table |\n"
#+END_SRC

#+RESULTS:
:RESULTS:
Hello

| table | table |
| table | table |
:END:

:results は言語毎にデフォルト値が異なるので注意を要する。デフォルト値や実際にどのヘッダー引数が使えるかは ob-<言語ID>.el の変数(org-babel-default-header-args:<言語ID>)や関数(org-babel-execute:<言語ID>)を見るのが手っ取り早いかもしれない。

その他にも様々なヘッダー引数がある。全ヘッダー引数のリストと説明はマニュアル(Specific header arguments – The Org Manual)を参照のこと。

noweb参照

(公式マニュアル: Noweb reference syntax – The Org Manual)

nowebとは文芸的プログラミング(Literate programming – Wikipedia)のツールなのだそうだ(noweb – Wikipedia)。

何はともあれ名前付きブロックを参照する書き方ができる。

まず名前付きのブロックを作る。

#+NAME: js-hello-example
#+BEGIN_SRC js :var suffix="world"
return "hello_" + suffix;
#+END_SRC

それを << 名前 >> という形式で参照する。

#+BEGIN_SRC js :noweb yes
function sayHello(){
    <<js-hello-example>>
}
return sayHello();
#+END_SRC

これは次のように展開される。

#+BEGIN_SRC js :noweb yes
function sayHello(){
    return "hello_" + suffix;
}
sayHello();
#+END_SRC

カッコで引数を与えると実行結果を受け取ることが出来るらしい。

#+BEGIN_SRC text :noweb yes
<<js-hello-example(suffix="moon")>>
#+END_SRC
hello_moon

公式マニュアルの関連箇所:

結果のキャッシュ

(公式マニュアル: cache – The Org Manual)

:cache yes を指定してあらかじめ実行しておくとエクスポートするたびにコードブロックを実行しなくて済む。

コードブロック内にコードブロックを書く方法

#+BEGIN_SRC#+END_SRC はネストできない。

#+BEGIN_SRC org
aaa
#+BEGIN_SRC org
bbb
#+END_SRC
ccc
#+END_SRC

これをエクスポートすると次のようになってしまう。

aaa
#+BEGIN_SRC org
bbb

ccc #+END_SRC

行頭にカンマを打つと良いらしい。

#+BEGIN_SRC org
,#+BEGIN_SRC org
*bold*
,#+END_SRC
#+END_SRC

上のように行頭にカンマを一つ表示させるために私は行頭にカンマを二つ打っている。

カンマを三つ打つとなぜかそのまま三つ表示される。

,,#+BEGIN_SRC org
*bold*
,,#+END_SRC

四つ打ってもそのまま四つ表示される。

,,,#+BEGIN_SRC org
*bold*
,,,#+END_SRC

行頭に二つ表示させたい場合はどうしたら良いんだろう。

言語毎の書き方

Emacs Lisp

Emacs LispはEmacsに組み込まれているため最も安定して使える。

Emacs LispのコードブロックはOrg文書中で次のように書ける。

Emacsのバージョンを表示するコードと結果は次の通り。

#+BEGIN_SRC emacs-lisp :exports both
(emacs-version)
#+END_SRC

#+RESULTS:
: GNU Emacs 25.3.50.1 (x86_64-w64-mingw32)
:  of 2017-09-20

#+BEGIN_SRC emacs-lisp#+END_SRC の間にカーソルを置いて C-c C-c を押すことで #+RESULTS: 以下が生成される。

ヘッダー引数 :exports には none code results both が指定でき、コード(リスティング)と結果をそれぞれエクスポートするかどうか指定できる。今回は both を指定しているためコードと結果の両方がエクスポートされる。実際にエクスポートすると次のようになる。

Emacsのバージョンを表示するコードと結果は次の通り。

(emacs-version)
GNU Emacs 25.3.50.1 (x86_64-w64-mingw32)
 of 2017-09-20

org-mode

orgの書き方を説明するためにorg文書の中にorgのコードブロックを書くことは良くある(まさにこの文書)。

例えば太字、表、コードブロックの書き方を例示したいときは次のように書く。

#+BEGIN_SRC org
*bold*
|a|0|
|b|0|
,#+BEGIN_SRC emacs-lisp
(concat "hello" "world")
,#+END_SRC
#+END_SRC

これをエクスポートすると今上でご覧のようにorgのソースコードが表示される。

このソースコードを実際にエクスポートしたときの見た目を併記したい時はどうするか。

:exports result:exports both を指定してorgコードブロックの実行結果も一緒に出力させれば良い。 org文書は本来プログラムではないので「orgコードブロックの実行」というのは何やら不思議な気もする。orgの実行方法は org-babel-execute:org 関数で定義されている。見てみると基本的にコードブロックの中身をそのまま返すだけとなっている。デフォルトは :results raw で返すので、結果はそのまま(生で)org文書の中に埋め込まれる。

#+BEGIN_SRC org :exports both :results raw replace
*bold*
|a|0|
|b|0|
,#+BEGIN_SRC emacs-lisp
(concat "hello" "world")
,#+END_SRC
#+END_SRC

これをエクスポートすると次のようにコードと結果が両方(both)表示される。

*bold*
|a|0|
|b|0|
,#+BEGIN_SRC emacs-lisp
(concat "hello" "world")
,#+END_SRC

bold

a 0
b 0
(concat "hello" "world")

デフォルトの :results (変数 org-babel-default-header-args:org) が :results silent なため、そのままでは結果が出力されない。明示的に :results replace と指定する必要がある。 (注意: :replace を指定しても再実行時に #+RESULTS: の部分を置き換えてくれず、以前の結果の上に新しい結果を追加してしまう場合がある。結果がどこまでか判別するすべがない場合にこの現象が起きる。結果が単一要素の場合は正しく置き換えてくれる)

HTMLやJavaScriptのところで紹介するように #+CALL を使う方法もある。

#+NAME: org-example
#+BEGIN_SRC org :exports both :results raw replace
*bold*
|a|0|
|b|0|
,#+BEGIN_SRC emacs-lisp
(concat "hello" "world")
,#+END_SRC
#+END_SRC

#+NAME: ref-org
#+BEGIN_SRC emacs-lisp :exports none :results raw :var ref=""
(cadr (org-babel-lob--src-info ref))
#+END_SRC

#+CALL: ref-org("org-example")

HTML

準備:

  • 使っているモード(web-mode等)に合わせて org-src-lang-mode の書き換えが必要。

    (add-to-list 'org-src-lang-modes '("html" . web))
    

org文書でHTMLの書き方を説明したい場合、org文書の中にHTMLのコードブロックを書くことになる。

例えば次のコードブロックは、HTMLでcanvas要素とscript要素を使って絵を書く例を示している。

#+BEGIN_SRC html :exports both
<div>
<canvas width="320" height="240" />
<script>
//<![CDATA[
  var canvases = document.getElementsByTagName("canvas");
  var canvas = canvases[canvases.length - 1]; //last canvas element
  var ctx = canvas.getContext("2d");
  var angle = 0;
  function draw(){
    ctx.fillStyle = "rgb(128, 128, 255)";
    ctx.fillRect(0, 0, 320, 240);

    ctx.fillStyle = "rgb(64, 64, 128)";
    ctx.beginPath();
    ctx.arc(160, 120, 110, 0, 2*Math.PI, false);
    ctx.fill();

    ctx.strokeStyle = "rgb(255, 255, 255)";
    ctx.lineWidth = 2;
    ctx.beginPath();
    ctx.moveTo(160, 120);
    ctx.lineTo(160+100*Math.sin(angle*Math.PI/180), 120-100*Math.cos(angle*Math.PI/180));
    ctx.stroke();
  }
  draw();
  setInterval(function(){ angle += 6; draw();}, 1000);
//]]>
</script>
</div>
#+END_SRC

当然「これをブラウザで見るとこうなりますよ」というようにHTMLの表示結果を併記したいのだが、素直にexportsにbothを指定しても結果はエクスポートされない。試しにC-c C-cでHTMLコードブロックを実行しようとすると失敗する。

org-babel-execute-src-block: No org-babel-execute function for html!

org-babel-execute:html が定義されていないのでそのままでは実行できない。

元々HTMLはプログラミング言語ではなくマークアップ言語なので、実行して結果が出るようなものではない。 しかしHTMLの解説をする場合に書き方とブラウザでの表示結果を併記したいことは良くあるし、そのために例として書いたマークアップをそのままエクスポートしたHTML文書に埋め込められれば便利だ。

解決方法は色々ある。

  1. noweb参照でコードの重複を避ける方法

    まず名前付きhtmlコードブロックを作成し、それを後からorgコードブロックから参照する。

    canvasを使う例:
    #+NAME: html-example
    #+BEGIN_SRC html :exports code
    <div>
    <canvas width="320" height="240" />
    <script>
    //<![CDATA[
      var canvases = document.getElementsByTagName("canvas");
      var canvas = canvases[canvases.length - 1]; //last canvas element
      var ctx = canvas.getContext("2d");
      var angle = 0;
      function draw(){
        ctx.fillStyle = "rgb(128, 128, 255)";
        ctx.fillRect(0, 0, 320, 240);
    
        ctx.fillStyle = "rgb(64, 64, 128)";
        ctx.beginPath();
        ctx.arc(160, 120, 110, 0, 2*Math.PI, false);
        ctx.fill();
    
        ctx.strokeStyle = "rgb(255, 255, 255)";
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(160, 120);
        ctx.lineTo(160+100*Math.sin(angle*Math.PI/180), 120-100*Math.cos(angle*Math.PI/180));
        ctx.stroke();
      }
      draw();
      setInterval(function(){ angle += 6; draw();}, 1000);
    //]]>
    </script>
    </div>
    #+END_SRC
    
    結果:
    #+BEGIN_SRC org :noweb yes :exports results :results raw replace
    #+BEGIN_EXPORT html
    <<html-example>>
    #+END_EXPORT
    #+END_SRC
    

    :results raw を使うのがミソ。rawはOrg形式としてそのまま文書に埋め込まれる。 :results org としてしまうと結果が #+BEGIN_SRC org#+END_SRC で囲われてしまうので注意。 #+BEGIN_EXPORT html :noweb yes と書ければ簡単なのだけど書けない。

  2. noweb参照とhereドキュメントで対処する方法

    1とほぼ同様だが、何かhereドキュメントが使える言語でコードブロックをそのままエクスポートする。 :results html は結果を #+BEGIN_EXPORT html で囲ってくれるので。

    #+BEGIN_SRC perl :noweb yes :results output html :exports results
    print<<EOF;
    <<html-example>>
    EOF
    #+END_SRC
    
  3. 実行関数を定義する方法

    org-babel-execute:html が定義されていないのが原因なので、素直に定義してしまえば良いという話。

       (defun org-babel-execute:html (body params) body)
    
    #+BEGIN_SRC html :results html :exports both :noweb yes
    <<html-example>>
    #+END_SRC
    
  4. #+CALL を使用する方法

    (参考: org mode – Export Javascript source block to script tag in HTML when exporting Org file to HTML – Emacs Stack Exchange)

    #+NAME: ref-html
    #+BEGIN_SRC emacs-lisp :exports none :results html :var ref=""
    (concat "<div>" (cadr (org-babel-lob--src-info ref)) "</div>")
    #+END_SRC
    
    #+CALL: ref-html("html-example")
    
  5. ob-browserを使用する方法

    ob-browser を使用するとPhantomJS経由でスクリーンショットを撮って画像化してくれる。

結果:


参考:

JavaScript

準備:

  • node.jsをインストールしてnodeコマンドへパスを通す。
  • 変数 org-babel-js-cmd を設定(確認)する。
  • 別のモード(js2-mode等)を使っている場合は org-src-lang-mode の書き換えが必要。

    (add-to-list 'org-src-lang-modes '("js" . js2))
    
  • org-babel-load-languages に '(js . t) を追加

例1(コンソールに出力した結果を併記する):

#+BEGIN_SRC js :results output :exports both :cache yes
class Person{
    constructor(name, age){
        this.age = age;
        this.name = name;
    }
    greet(){
        return "my name is " + this.name + " " + this.age;
    }
}
var hanako = new Person("Kikuko", 17);
console.log(hanako.greet());
#+END_SRC

コードブロック内のJavaScriptではconsole.logを使って結果を出力している。:resultsにoutputを指定することで標準出力に出力されたものを結果として扱う。

結果:

my name is Kikuko 17

例2(コードブロックに変数で値を引き渡し、結果をreturnで返す例):

#+BEGIN_SRC js :results value :exports both :cache yes :var count=3
return Array.from(Array(count).keys());
#+END_SRC

ヘッダー引数 :var count=3 でJavaScriptへ値を引き渡している。JavaScriptのコードは配列 [0,1,2] をreturnで返している。結果はtableの形で表示される。

結果:

0 1 2

例3(HTML文書に埋め込む例):

コードブロック内のJavaScriptを、エクスポート後のHTML文書内に埋め込みたい場合もある。

最後の要素の親の親(最後のscript要素の親)へdiv要素を追加する例:

#+NAME: js-example
#+BEGIN_SRC js :exports code
(function(){
    var lastNode = document.body;
    while(lastNode.lastChild){ lastNode = lastNode.lastChild;}
    var div = document.createElement("div");
    div.innerHTML = "Hello World from JavaScript Code";
    div.style = "border: 1px solid;";
    lastNode.parentNode.parentNode.appendChild(div);
})();
#+END_SRC

実際にやってみる:

#+NAME: ref-js
#+BEGIN_SRC emacs-lisp :exports none :results html :var ref=""
(concat "<script>" (cadr (org-babel-lob--src-info ref)) "</script>")
#+END_SRC

#+CALL: ref-js("js-example")

↑ここに見える?

(参考: org mode – Export Javascript source block to script tag in HTML when exporting Org file to HTML – Emacs Stack Exchange)

Java

準備:

  • JDKをインストールする。
  • 変数を設定するかパスを通す。
    • org-babel-java-compiler (default: javac) (%JAVA_HOME%/bin/javac)
    • org-babel-java-command (default: java)
  • org-babel-load-languages に '(java . t) を追加

Javaのコードを実行するにはメインのクラス名を :classname で指定する必要がある。

#+BEGIN_SRC java :results output :exports both :classname HelloWorld :cmdline -Dorgmode.arg=test1234 :cache yes
public class HelloWorld {
    public static void main(String[] args){
        System.out.println("Hello");
        System.out.format("orgmode.arg=%s", System.getProperty("orgmode.arg"));
    }
}
#+END_SRC
Hello
orgmode.arg=test1234

変数(:var)や引数を渡す仕組みはない(Org9.1時点。org-babel-execute:javaを参照)。無理矢理やるならcmdlineとシステムプロパティを使うくらいか?

C/C++/D

準備:

  • 変数を設定する。
    • org-babel-C-compiler (default:gcc)
    • org-babel-C++-compiler (default:g++)
    • org-babel-D-compiler (default:rdmd)
  • org-babel-load-languages に '(C . t) を追加

例1:

#+HEADER: :includes <iostream> <cmath>
#+HEADER: :var x=1.0 :var y=2.0
#+BEGIN_SRC C++ :exports results :results output :cache yes
std::cout << "hello " << M_PI << std::endl;
std::cout << "x=" << x << " y=" << y << std::endl;
#+END_SRC
hello 3.14159
x=1 y=2

例2:

#+BEGIN_SRC C++ :exports results :results output table :cache yes
#include <iostream>

int main(int argc, char *argv[]){
    std::cout << 123 << " " << 456 << '\n'
              << 789 << " " << 012 << std::endl;
}
#+END_SRC
123 456
789 10

例3:

#+HEADER: :includes <iostream> <vector> <utility>
#+BEGIN_SRC C++ :exports both :cache yes
std::vector<std::pair<int, int>> v{{0,1}, {2,3}, {4,5}};
for(const auto &e : v){
    std::cout << e.first << ',' << e.second << '\n';
}
#+END_SRC
0 1
2 3
4 5

ditaa

準備:

  • ditaa.jarをどこかに配置する。(http://ditaa.sourceforge.net/#download)
  • 変数を設定する。
    • org-ditaa-jar-path
    • org-ditaa-jar-option
    • org-ditaa-eps-jar-path
  • org-babel-load-languages に '(ditaa . t) を追加
#+BEGIN_SRC ditaa :file ditaa-example.png :exports both :cache yes
+--------+   +-----------+   +-------------+
| Source +-->+ Processor +-->+ Destination |
+--------+   +-----------+   +-------------+
#+END_SRC
2017-10-26-ditaa-example.png

書き方等についてはditaaを参照のこと。

PlantUML

準備:

  • plantuml.jar をどこかに置いて org-plantuml-jar-path を設定すること。
  • plantumlの動作にはgraphvizのインストールと環境変数 GRAPHVIZ_DOT の設定が必要。
  • graphvizはCygwinのパッケージになっている。
  • org-babel-load-languages に '(plantuml . t) を追加

クラス図を描く例:

#+BEGIN_SRC plantuml :file plantuml-example.png :exports results :cache yes
World "1" *-right- "0..*" Animal : contains
Animal <|-- Dog
Animal <|-- Cat

World : void moveAllAnimals(double dt)
Animal : double age
Animal : double getAge()
Animal : void move(double dt)
Dog : void move(double dt)
Cat : void move(double dt)

note top of Animal
  Base class of all animals.
end note
#+END_SRC
2017-10-26-plantuml-example1.png

PlantUML自体については公式サイトを参照のこと。

dot

準備:

  • dotコマンドへパスを通しておく(一応:cmdヘッダーでも指定できるがおすすめはしない。ちなみに:cmdlineヘッダーも有効)
  • graphvizはCygwinのパッケージになっている。

適当な有向グラフを描く例:

#+BEGIN_SRC dot :file dot-example.png :exports results :cache yes
digraph {
  a -> b
  b -> c
  a -> c
}
#+END_SRC
2017-10-26-dot-example.png

dot自体の書き方については Graphviz | Graphviz – Graph Visualization Software を参照のこと。

R

準備:

  • インストールはインストーラで簡単
  • 変数 org-babel-R-command にRコマンドへのパスとコマンドライン引数を設定する
  • org-babel-load-languages に '(R . t) を追加

データを用意:

#+NAME: age-score-table
| Age | Score |
|-----+-------|
|  10 |    82 |
|  15 |   100 |
|   8 |    52 |
|  13 |    75 |
|  12 |    38 |
|   9 |    80 |
|  13 |    92 |
|  11 |    65 |
|  15 |    85 |
|  18 |    98 |
|   3 |    20 |
|  15 |    92 |
|  14 |    78 |
|  12 |    53 |
Age Score
10 82
15 100
8 52
13 75
12 38
9 80
13 92
11 65
15 85
18 98
3 20
15 92
14 78
12 53

org-mode表から散布図を描く:

#+BEGIN_SRC R :var table=age-score-table :results output graphics :file r-plot.png :width 320 :height 320 :cache yes
plot(table)
abline(lm(table$Score ~ table$Age), col="red")
#+END_SRC
2017-10-26-r-plot.png

org-mode表からヒストグラムを描く:

#+BEGIN_SRC R :var table=age-score-table :results output graphics :file r-hist.png :width 320 :height 320 :cache yes
hist(table$Age)
#+END_SRC
2017-10-26-r-hist.png

org-mode表から年齢別スコアを集計(結果を表で表示する例):

#+BEGIN_SRC R :var table=age-score-table :results value :colnames yes :exports results
aggregate(x=list(Score=table$Score),by=list(Age=table$Age),FUN=function(x)c(Mean=mean(x), Count=length(x), Max=max(x), Min=min(x)))
#+END_SRC
Age Score.Mean Score.Count Score.Max Score.Min
3 20 1 20 20
8 52 1 52 52
9 80 1 80 80
10 82 1 82 82
11 65 1 65 65
12 45.5 2 53 38
13 83.5 2 92 75
14 78 1 78 78
15 92.3333333333333 3 100 85
18 98 1 98 98

:colnames yes:rownames yes を付けないと列名や行名を取りこぼす。

R Source Code Blocks in Org Modeに書いてあるようにasciiパッケージを使用してOrg形式で出力し、 :result output で受ける方法もある。

好きな関数をプロットする例:

#+BEGIN_SRC R :results output graphics :file r-function.png :width 320 :height 320 :cache yes
y <- function(x){return (sqrt(x))}
plot(y, 0, 1)
#+END_SRC
2017-10-26-r-function.png

R自体については R: The R Project for Statistical Computing を参照のこと。

結果の受け取り方

:results table

Emacs Lisp

#+BEGIN_SRC emacs-lisp :results table :exports results
'((1) (1 2) (3 4 5))
#+END_SRC
1    
1 2  
3 4 5

Java

#+BEGIN_SRC java :classname HelloWorld :results table :cache yes
class HelloWorld {
    public static void main(String[] args){
        final String[] hand = {"Guu", "Choki", "Paa"};
        System.out.println("\t" + hand[0] + "\t" + hand[1] + "\t" + hand[2]);
        for(int i = 0; i < 3; ++i){
            System.out.printf(hand[i]);
            for(int j = 0; j < 3; ++j){
                System.out.printf("\t%d", (4+j-i)%3-1);
            }
            System.out.printf("\n");
        }
    }
}
#+END_SRC
  Guu Choki Paa
Guu 0 1 -1
Choki -1 0 1
Paa 1 -1 0

:results list

#+BEGIN_SRC emacs-lisp :results list :exports results
'("orange" "apple" "banana")
#+END_SRC
  • orange
  • apple
  • banana

:results scalar

#+BEGIN_SRC emacs-lisp :results scalar :exports results
'("orange" "apple" "banana" ("tenpura" "sukiyaki"))
#+END_SRC
("orange" "apple" "banana" ("tenpura" "sukiyaki"))

:results pp

#+BEGIN_SRC emacs-lisp :results pp :exports results
'("orange" "apple" "banana" ("tenpura" "sukiyaki"))
#+END_SRC
("orange" "apple" "banana"
 ("tenypura" "sukiyaki"))

:results file

#+BEGIN_SRC emacs-lisp :results file :exports results :cache yes
(let ((filename "2017-10-26-file-result-example.txt"))
  (with-temp-buffer (insert "orange apple banana") (write-region (point-min) (point-max) filename))
  filename)
#+END_SRC

2017-10-26-file-result-example.txt

コードブロックの呼び出し

まず名前付きのブロックを用意する。 次のコードは、標準出力へは”<b>hello world</b>”を出力し、値は123を返す。

#+NAME: call-ex1
#+BEGIN_SRC perl :var suffix=" world" :results value :cache yes :exports both
printf "<b>hello,$suffix</b>";
123
#+END_SRC
123

この名前付きブロックを呼び出す。

#+CALL: call-ex1[:results output](suffix=" moon") :results html

inline calling result: call_call-ex1[:results output](suffix=" moon")[:results html]

結果は次。

hello, moon

inline calling result: hello, moon

引数の前に指定するヘッダーは、呼び出し先ブロックに対して使われる。引数の後に指定するヘッダーは、得られた結果に対して使われる。

コードブロックから表を参照する方法

表に名前 #+NAME でを付けると :var 変数名 = 表名 で表の中身を参照できる。

#+NAME: payment-table
| 科目   | 金額 |
|--------+------|
| 交通費 |  320 |
| 食費   |  500 |
| 交通費 |  120 |
| 食費   |  140 |
| 交通費 |  300 |
| 食費   |  550 |

#+BEGIN_SRC emacs-lisp :var payments=payment-table :colnames yes
(let (alist)
  (loop for line in payments do
        (let* ((class (nth 0 line))
               (amount (nth 1 line))
               (cell (or (assoc class alist)
                         (car (push (list class 0) alist)))))
          (setcar (cdr cell) (+ (cadr cell) amount))))
  alist)
#+END_SRC

#+RESULTS:
| 科目   | 金額 |
|--------+------|
| 食費   | 1190 |
| 交通費 |  740 |
2017-10-22

Emacsでイタリック(斜体)が表示されないのを何とかした(Windows Emacs25.3)

org-modeを使っていて、ふと斜体が表示されないのに気がつきました。

私の最近のフォント設定は前回の通り次のような単純な物でした。

;; 記号をデフォルトのフォントにしない。(for Emacs25.2)
(setq use-default-font-for-symbols nil)
;; デフォルトはASCII用のフォントでなければダメっぽい。
(set-face-attribute 'default nil :family "Inconsolata" :height 120)
;; ASCII以外を指定する。
(set-fontset-font nil '(#x80 . #x10ffff) (font-spec :family "MS Gothic"))

ASCII部分はプログラミング用フォントとして有名なInconsolataを使っています。 それ以外は基本的にMS ゴシック。私はMS ゴシックの低解像度ディスプレイ下でのシャープさをとても評価しているのです。

それでまず試したのはマニュアル(Bold and italic – GNU Emacs FAQ For MS Windows)にもあるこの設定。

(setq w32-enable-synthesized-fonts t)
(set-face-font 'italic "-*-Courier New-normal-i-*-*-11-*-*-*-c-*-iso8859-1")
(set-face-font 'bold-italic "-*-Courier New-bold-i-*-*-11-*-*-*-c-*-iso8859-1")

んー、確かに斜体になります。でもCourier Newは嫌なのでこれをInconsolataなどにしてみてもうまく行きません。MS Gothicなどでもダメです。Consolas等あらかじめ斜体が用意されているフォントならうまくいきます。

ひょっとしたら計算で傾かせている場合はダメなのでしょうか。でも昔は傾いたと思うのですが……。 w32-enable-synthesized-fonts を調べてみましたが、これ現在はobsoleteで何の効果も無いみたいです。ソースを過去に遡って追ってみましたが、Emacs23になってからはどこからも使われていないみたいです。 色々試してみてもどうあがいても斜体がないフォントを斜体にすることができませんでした。

仕方が無いので斜体がある等幅フォント(日本語あり)ということで、Ricty Diminishedを使ってみました。

(set-face-font 'italic "Ricty Diminished:italic")

うん、斜体になります。……でも、日本語は斜体になっていません。あれー????

日本語部分はMS Gothic(非斜体)のままです。ASCII部分は設定の通りRicty Diminishedの斜体。上のフォントセットの設定が優先されているのでしょうか?

斜体専用のfontsetを作ってASCIIもそれ以外もRicty Diminishedにし、italicフェイスのfont属性に設定してみましたが、やはり日本語(非ASCII)はMS Gothic(非斜体)です。

諦めかけたところでふと (describe-face 'default) のfontset:の項目が目に付きました。あれ、faceの属性にもfontsetってあるんですね。試しに (set-face-attribute 'italic nil :fontset "fontset-standard") とやってみるとエラーが出ません。もしかして……と思い、Ricty Diminishedだけのfontsetを:fontset属性に設定してみると、無事日本語も含めて斜体はRicty Diminishedになりました。

なるほどー、italicフェイスのfontset属性がunspecifiedだとデフォルトのfontset(defaultフェイスのfontset属性?)が使われて上で設定したMS Gothicが使われてしまうんですね。だからitalicフェイスのfontset属性で再度非ASCII用のフォントを指定してあげれば良いわけですか。

というわけで、最終的な設定は次のようになりました。

;; 記号をデフォルトのフォントにしない。(for Emacs25.2)
(setq use-default-font-for-symbols nil)

(defun my-font-available-p (name) (find-font (font-spec :name name)))
(cond
 ;; ASCII用のフォントを設定する。
 ;; Inconsolataを優先する。理由:
 ;; - 等幅プログラミング用フォント
 ;; - Windows上でのhintingが良いのでRictyより文字がぼやけない
 ((my-font-available-p "Inconsolata") (set-fontset-font nil 'ascii "Inconsolata-12") (setq-default line-spacing 0.0))
 ((my-font-available-p "Ricty Diminished") (set-fontset-font nil 'ascii "Ricty Diminished-12") (setq-default line-spacing 0.2))
 ((my-font-available-p "Consolas") (set-fontset-font nil 'ascii "Consolas-12")))
;; ASCII以外のフォントを設定する。
(set-fontset-font nil '(#x80 . #x3fffff) "MS Gothic")
;; 斜体フォントを設定する。
;; faceのfontset属性を設定するところがミソ。そうでないと上で設定した非ASCII用フォントが優先されてしまう。
(cond
 ;; Ricty Diminishedを使う。理由:
 ;; - ASCIIにも日本語文字にも斜体バージョンがある(実際には独自にFontForgeで少し角度を増やした物を使っています。その際フォント情報も調整しました)
 ;; - 日本語も等幅である
;;  - Inconsolataと同じプログラミング用フォント
 ;; - Inconsolataには斜体バージョンがない
 ;; - hintingや文字の高さの違いは斜体に限り諦められる
 ((my-font-available-p "Ricty Diminished")
  (create-fontset-from-fontset-spec "-*-*-*-italic-*-mono-*-*-*-*-*-*-fontset-myitalic")
  (set-fontset-font "fontset-myitalic" '(#x80 . #x3fffff) "Ricty Diminished")
  (set-face-attribute 'italic      nil :fontset "fontset-myitalic")
  (set-face-attribute 'bold-italic nil :fontset "fontset-myitalic"))
)

本当は日本語部分はMS Gothicの斜体にしたかったのですが、どうあがいても出来なかったので仕方がありません。日本語の斜体を使う機会は多くはありませんし諦めます。

script slant フォント
ascii normal Inconsolata
非ascii normal MS Gothic
ascii italic Ricty Diminished
非ascii italic Ricty Diminished

という組み合わせで使いたいという人はあまりいないかもしれませんが、ひとまずこんな感じで。

それにしても set-face-attribute の説明に :fontset のことが書いていないのですが大丈夫なのでしょうか。実際常に変更できるわけではないようで、少なくともdefaultフェイスに対する:fontset属性の変更は何故かうまくいきませんでした。defaultフェイスはフレームパラメータと結びついているので制約があるのでしょうか?

一番最初にASCII用のフォントを設定するところですが、同じ事を次のようにも書けます。

(set-face-attribute 'default nil :font "Inconsolata-12")
defaultフェイスのフォント関連属性を変更することで、フレームのfontパラメータも書き換わります。自動的に fontset-auto1 のようなfontsetが作られます。 :family "Inconsolata" :height 120 のような指定をするとfontset-auto1とfontset-auto2の二つが作られたりします。
(set-frame-font "Inconsolata-12") または (set-frame-parameter nil 'font "Inconsolata-12")
フレームのfontパラメータを書き換えるとdefaultフェイスも書き換わります。自動的に fontset-auto1 のようなfontsetが作られます。
(set-fontset-font "fontset-startup" 'ascii "Inconsolata-12")
今回採用した方法とほぼ同じです。起動直後はfontset-startupがフレームに設定されているため、”fontset-startup”と書いてもnilと書いても同じです。余分なfontsetは自動的に作られません。

フレーム、フレームのdefaultフェイス、フレームに現在設定されているfontsetのいずれを修正しても同じような挙動になります。

いやはや、Emacsのフォントまわりは本当に難解ですね。