2011-02-10

Emacs でバイナリ形式の .plist を編集する

Mac OS X の .plist はテキスト形式とバイナリ形式があります。
Xcode 付属の Property List Editor で編集できますが、できれば Emacs を使いたい。

元ネタ
Edit and save binary plist files
http://hints.macworld.com/article.php?story=2005061422012079

auto-compression-mode で対処する方法が紹介されてますが、これだとバイナリ形式ではない .plist でもバイナリ形式で保存してしまったりと不具合があります。
その記事のコメントに別の方法が投稿されていますが、それでもまだ若干問題があります。

  • バイナリ形式ではない .plist を開くと xml-mode にならない
  • 書き込み権限のないバイナリ形式の .plist を開くことができない
  • 日本語等が文字化けする (Emacs22)

その問題点を改良したものがこちら。

;; Edit and save binary plist files
;; http://hints.macworld.com/article.php?story=2005061422012079
(add-to-list 'auto-mode-alist '("\\.plist\\'" . visit-bplist))
(add-to-list 'auto-mode-alist '("\\.nib\\'" . visit-bplist))

(add-to-list 'magic-mode-alist '("\\`bplist" . visit-bplist))
(add-to-list 'auto-coding-regexp-alist '("\\`bplist" . utf-8))

(defvar plist-converted-binary nil
  "Buffer local variable indicating if file came from binary-plist.")
(make-variable-buffer-local 'plist-converted-binary)

(defun visit-bplist ()
  (let (bplist)
    (when (string-match "\\`bplist" (buffer-string))
      (setq bplist t)
      (save-excursion
        (let (buffer-read-only)
          (message "Reading in binary plist")
          (erase-buffer)
          (let ((process-coding-system-alist '(("plutil" . utf-8))))
            (call-process "plutil" nil t nil
                          "-convert" "xml1" "-o" "-" (buffer-file-name))))))
    (xml-mode)
    (when bplist
      (set-buffer-modified-p nil)
      (setq buffer-undo-list nil)
      (setq plist-converted-binary t))))

(defadvice save-buffer (after convert-plist (&optional args))
  (when plist-converted-binary
    (shell-command
     (format "/usr/bin/plutil -convert binary1 %s"
             (shell-quote-argument (buffer-file-name))) nil nil)
    (message "Wrote bplist %s" (buffer-file-name))))
(ad-activate 'save-buffer)

動作確認は Mac OS X 10.6 と GNU Emacs 22 でしています。