平衡点


2011/12/13

_ Emacsの設定ファイルをorgで書く[Emacs

この日記はEmacs Advent Calendar 2011の13日目です. 前日はid:handlenameさんのalign設定用例集でした.

勢いで申し込んでみたものの, 何を書こうか迷ってしまいました. 最近やった事といえば「Emacsの設定ファイルをorgで書く」ぐらいなので, 今日はそのお話です.

org-mode?

もはや説明不要な気もしますが org-mode は非常に高機能なアウトライン記述用のメジャーモードです. 私は最近殆ど全てのモンをorg-modeを使って記述しています.

org-modeはかなり高機能で, コードを見るたびに「こんな事もできるのか!」と驚愕することが多いです. 今日のお題はその中の「org-babel」を使ったお話です.

org-babel?

org-babelを使うとorgファイル内に別の言語のコードブロックを記述して, 出力結果をorgと一緒にアレコレすることができます.

今のところ 39 の言語に対応している(git のファイルだけみると 45 個ありますが)みたいですね.

Fortran なんか誰得感が...(オレ得?)

おもしろいのはorg-babelでEmacsの設定ファイルを記述する事ができる点です. 最近は init-loader とか使って設定ファイルを単一の.emacs.d/init.el から複数のファイルに分割している人も多いと思いますが, init.el あたりには org の load-path 設定あたりを書いておいて, 他の設定ファイルは org で書く, とかできるわけです.

つまり, 今まで適宜コメントを付記して書いていたemacs-lispファイルを org + org-babel で文章主体で書けるようになるわけです.

org-babel で emacs を設定する?

やることは簡単です. init.el で (require 'org-install) した後で org-babel-load でファイルを読むだけです. 例えば init.el に

(require 'org-install)
(defvar org-startup-dir (concat user-emacs-directory "site-start.d/"))
(org-babel-load-file (expand-file-name "init.org" org-startup-dir))

とか書いておいて, ~/.emacs.d/site-start.d/init.org に設定を記述していきます.

例えば ~/.emacs.d/site-start.d/ 以下に設定ファイルを集めている場合は init.org に

#+TITLE: Emacs の基本設定
#+OPTIONS: toc:2 num:nil ^:nil
* 言語の設定
...
* 外部ファイルで設定する
** org  で書かれた設定ファイルを読み込む関数
#+begin_src emacs-lisp
(defun my:load-org-file (file)
 "load org file"
 (org-babel-load-file (expand-file-name file org-startup-dir)))
#+end_src
...

という関数を定義しておくと,

(my:load-org-file "ddskk.org")

で ~/.emacs.d/site-start.d/ddskk.org が読み込まれます.

org-babel-load-file?

org-babel-load-file は ob-tangle.el で定義されていて

(defun org-babel-load-file (file)
  "Load Emacs Lisp source code blocks in the Org-mode FILE.
This function exports the source code using
`org-babel-tangle' and then loads the resulting file using
`load-file'."
  (interactive "fFile to load: ")
  (flet ((age (file)
              (float-time
               (time-subtract (current-time)
                              (nth 5 (or (file-attributes (file-truename file))
                                         (file-attributes file)))))))
    (let* ((base-name (file-name-sans-extension file))
           (exported-file (concat base-name ".el")))
      ;; tangle if the org-mode file is newer than the elisp file
      (unless (and (file-exists-p exported-file)
                   (> (age file) (age exported-file)))
        (org-babel-tangle-file file exported-file "emacs-lisp"))
      (load-file exported-file)
      (message "loaded %s" exported-file))))

となっています. つまり

  1. 指定された org ファイルの basename を取得
  2. 取得した basename + ".el" と元の org ファイルのタイムスタンプを比較
  3. .el のタイムスタンプが古かったら, org 中の #+begin_src emacs-lisp 〜 #+end_src 部分をファイル名.el というファイルに抽出する
  4. タイムスタンプが新しい or .el の抽出を行なったら .el を読む

ということをしています.

org-babel-load-file + byte-compile

というわけで org で設定ファイルを記述できるようになりました. これで

  • 「この設定なんだったっけ?」

とか

  • 「私の設定はこんな感じです」

とかがやりやすくなりました(違

でも org-babel-load-file は .el の抽出までしかやってくれません. .el があったら byte-compile したくなるのが人情です. また make 一発で全て byte-compile したいですよね?

というわけで(毎度 ad hoc に)ちょっと弄ってみました. 以下を ~/.emacs.d/init.el に書いておきます.

;;; org-babel
;;
;; Emacs の設定は org-mode で記述.
;;
(require 'org-install)
(defun my:org-babel-tangle-and-compile-file (file)
  "export emacs-lisp and byte-compile from org files (not load).
   originally ob-tangle.el"
  (interactive "fFile to load: ")
  (flet ((age (file)
              (float-time
               (time-subtract (current-time)
                              (nth 5 (or (file-attributes (file-truename file))
                                         (file-attributes file)))))))
    (let* ((base-name (file-name-sans-extension file))
           (exported-file (concat base-name ".el"))
           (compiled-file (concat base-name ".elc")))
      ;; tangle if the org-mode file is newer than the elisp file
      (unless (and (file-exists-p compiled-file)
                   (> (age file) (age compiled-file)))
        (org-babel-tangle-file file exported-file "emacs-lisp")
        (byte-compile-file exported-file)))))

(defun my:org-babel-load-file (file)
  "load after byte-compile"
  (interactive "fFile to load: ")
  (my:org-babel-tangle-and-compile-file file)
  (load (file-name-sans-extension file)))

(defvar org-settings-dir (concat user-emacs-directory "site-start.d/"))
(defun my:load-org-file (file)
  "org-settings-dir 以下から my-org-babel-load-file"
  (my:org-babel-load-file (expand-file-name file org-settings-dir)))

*1

これで

  • 設定ファイルの byte-compile 時には my:org-babel-tangle-and-compile-file
  • 設定ファイルの読み込み時は (my:load-org-file "hogehoge")
    • hogehoge.org の#+begin_src emacs-lisp 〜 #+end_src 部分を hogehoge.el に抽出
    • hogehoge.el を byte-compile -> hogehoge.elc を生成
    • hogehoge.elc を load

となりました. まとめて byte-compile する時には Makefile あたりに

%.elc: %.org
      $(EMACS) --batch -l $(HOME)/.emacs.d/init.el --no-site-file \
        --eval '(mapc (lambda (x) (my:org-babel-tangle-and-compile-file (symbol-name x))) (quote ($(CURDIR)/$<)))'

とでも書いておくと良いでしょう.

まとめ?

というわけで「Emacs の設定ファイルを org で書く」というお話でした. 誰得感がありますが, コメントだけだと辛い場合に org で説明を書けるのは良いですね. またアウトライナーですから長くなりがちな解説部分を折り畳んで表示できるのも気にいっています.

最近, Emacs の設定を見直すと同時に org に変更 + html 化を進めています. 今日書いた内容は

にあります.

github にも up してあります. github は org も html で表示してくれるみたいですが, 欲を言えば org-babel 部分を適宜 syntax highlight するなり, code block として表示してくれるようになると良いのですけれどね.

明日はid:mhayashi1120の予定です.

*1 どーでも良いですが, google-code-pretty の syntax highlighter ってイマイチですね. んー.


2011/12/20

_ THANX - Best of Die in Cries -[CD

昔の音源ひっぱり出してきたのだけれど, 聞きたい曲が無かったので中古屋巡り(今, 見たら Amazon にもあった)

THANX-ベスト・オブ・ダイ・イン・・クライズ THANX-ベスト・オブ・ダイ・イン・・クライズ
DIE IN CRIES, BMGビクター

最近ずっと聞いてる...んー。


2011/12/21

_ RD スタイルで CodeRay のシンタックスハイライトを[Ruby] [tDiary

最近, ソースコードの色付けに google-code prettify を使っていたのだけれど,

  1. イマイチしっくりこない(笑)
  2. autopagerize などで継ぎ足されると動作しない

というのが気になってた.

どうしようかなぁ, と思っていたら

と. そのものズバリでした. 須藤さん, 流石です. というわけで, 導入ついでに tDiary を 3.1.1 に上げてみたり.

以下はテスト

# source: ruby
 #!/usr/bin/env ruby
 require 'fileutils'

 # ディレクトリ内のファイルリスト. .svn と *.orig, .,  .., .git は無視
 dir = Dir.glob('.*').reject{|ign|
   ign =~ /((^\.svn)|(^\.*$)|(\.orig$)|(\.gpg$)|(^\.git)|(\.elc$))/
 }
 # 既存ファイルのバックアップを dotfiles/backup 以下に作成する
 backupd = Dir.pwd + '/backup'
 Dir.mkdir(backupd) unless FileTest.exist?(backupd)
 backupdir = backupd + "/" + Time.now.strftime("%Y%m%d-%H%M%S").to_s
 Dir.mkdir(backupdir) unless FileTest.exist?(backupdir)
 # メイン
 dir.each do |file|
   # ソースファイル
   dotfile = Dir.pwd + '/' + file
   # symlink の位置
   target = ENV['HOME'] + '/' + file
   # バックアップの位置
   backup = backupdir + '/' + file
   # ファイルが存在する場合
   if FileTest.exist?(target)
     # バックアップへの退避
     Flie.delete(target) if FileTest.symlink?(backup)
     FileUtils.move(target, backup) if FileTest.file?(target)
     FileUtils.move(target, backup) if FileTest.directory?(target)
     File.delete(backup) if FileTest.symlink?(backup)
     # symlink 作成
     File.symlink(dotfile, target)
   else
     # symlink 作成
     File.symlink(dotfile, target)
   end
 end

 # backup direcotry が空なら削除
 if Dir.entries(backupdir).reject{|i| i=~ /^\.*$/}.size == 0
   Dir.delete(backupdir)
   if Dir.entries(backupd).reject{|i| i=~ /^\.*$/}.size == 0
     Dir.delete(backupd)
   end
 end

 puts <<-EOS
 making symlink in ~/.
 if dotfile exist. mv ./backup/,
 but dotfile is symlink, delete it.
 if ./backup is empty, delet backup directory.
 EOS

2011/12/22

_ んー.

やること大杉 + 時間無い...という愚痴

_ CodeRay のバージョンを上げてみるテスト[Ruby

lisp のシンタックスハイライトが聞くと良いんだけれど, どうかな?

# source: lisp
;;; ob-tangle より自分用に幾つか関数を設定
;;
;;; my:org-babel-tangle-and-compile-file
;;
;; 指定された org ファイルから emacs-lisp を export してbyte-compile する.
;; - Make から呼ぶ事も想定しているので load はしない.
;;
(defun my:org-babel-tangle-and-compile-file (file)
  "export emacs-lisp and byte-compile from org files (not load).
   originally ob-tangle.el"
  (interactive "fFile to load: ")
  (flet ((age (file)
              (float-time
               (time-subtract (current-time)
                              (nth 5 (or (file-attributes (file-truename file))
                                         (file-attributes file)))))))
    (let* ((base-name (file-name-sans-extension file))
           (exported-file (concat base-name ".el"))
           (compiled-file (concat base-name ".elc")))
      ;; tangle if the org-mode file is newer than the elisp file
      (unless (and (file-exists-p compiled-file)
                   (> (age file) (age compiled-file)))
        (org-babel-tangle-file file exported-file "emacs-lisp")
        (byte-compile-file exported-file)))))

...駄目か. やっぱそんなに簡単には書けないか.

Fortran と lisp に対応できたら文句無いんだけれどなぁ...


2011/12/23

_ Firefox+vimperator で \C-j を無効化[Computer

入力が ibus-skk or uim-skk なので試しに設定してみたらあまりに快適だったのでメモ

vimperatorrc の適当な所に

map <C-j> <Nop>

と書いておくだけで OK.

_ dh_ruby が動きませぬ.[Computer] [Debian] [Ruby

はて...?

/usr/lib/ruby/vendor_ruby/1.8/rubygems/requirement.rb:179: \
  in `fix_syck_default_key_in_requirements': \
  uninitialized constant Gem::SyckDefaultKey (NameError)
...

ああ, コレですか

さて, どうするかな...?


2011/12/26

_ USB HDD を新調[Computer

バックアップとかデータ持ち歩きに使っていた USB HDD の電源ケーブルが断線気味で怖くて使えないので, ディスクを新調.

LaCie USB3.0/2.0対応2.5インチ外付ポータブルHDD Porscheデザイン 1TB LCH-MPS1TU3S LaCie USB3.0/2.0対応2.5インチ外付ポータブルHDD Porscheデザイン 1TB LCH-MPS1TU3S
ラシー

中身は(syslog 抜粋)

kernel: usb 2-1.3: new high speed USB device number 10 using ehci_hcd
kernel: usb 2-1.3: New USB device found, idVendor=174c, idProduct=5106
kernel: usb 2-1.3: New USB device strings: Mfr=2, Product=3, SerialNumber=1
kernel: usb 2-1.3: Product: AS2105
kernel: usb 2-1.3: Manufacturer: ASMedia
kernel: usb 2-1.3: SerialNumber:      WD-WX61A71D2047
kernel: scsi12 : usb-storage 2-1.3:1.0
kernel: scsi 12:0:0:0: Direct-Access     WDC WD10 TPVT-00U4RT1     01.0 PQ: 0 ANSI: 0
kernel: sd 12:0:0:0: [sdb] 1953525168 512-byte logical blocks: (1.00 TB/931 GiB)

ということです*1.現在データ転送中...

*1 ちなみに, 早速データ転送始めたらいきなり I/O エラーが出てディスクが見えなくなったりして...久々に初期不良を引き当てたみたいです. Orz


2011/12/27

_ Infographic in Debian[Debian

@noritada さんの呟きで知ったのけど:

カッコイイね.


連絡先など
portrait
最近の日記
一覧
Back to Top ▲