ラベル Mac OS X の投稿を表示しています。 すべての投稿を表示
ラベル Mac OS X の投稿を表示しています。 すべての投稿を表示

2011-04-03

Spotlight の検索結果や、スマートフォルダを Dired で表示する mdfind-dired.el

GNU Emacs に含まれる find-dired.el は指定ディレクトリ以下を find コマンドで検索し、結果を Dired で表示してくれます。
それを Spotlight のコマンドライン版である mdifnd で動くように修正を加えたものが mdfind-dired.el です。

できることは

  • Spotlight 検索を Emacs から実行し、その結果を Dired で表示する
  • スマートフォルダ (.savedSearch) を Dired で開く

動作環境

GNU Emacs 22 と 23。 Mac OS X 10.4 以上ですが、一部使えないコマンドがあるので 10.5 以上が推奨です。
GNU Emacs 23 と Mac OS X 10.6 でテストしています。

インストール

mdfind-dired.el
https://gist.github.com/900452

gist から raw をクリックし、 mdfind-dired.el を保存する。
load-path の通った場所にファイルを置き、以下のコードを ~/.emacs.el または ~/.emacs.d/init.el に加える。
(バイトコンパイルは任意です。)

(require 'mdfind-dired)
(add-to-list 'auto-mode-alist
             '("\\.savedSearch\\'" . mdfind-dired-change-to-dired))

キーバインドの設定は hook でします。

(add-hook 'mdfind-dired-hook
          (lambda ()
            (local-set-key "," 'mdfind-dired-toggle-visibility)))

使い方

mdfind の使い方は man ページ man mdfind に載っています。

M-x mdfind-dired
mdfind に生の検索語を入力し、結果を Dired で表示。
検索語は mdfind に渡す前にシェルに渡されるので、" * () & | $ 等の文字はエスケープする必要がある。(他のコマンドではエスケープする必要はない。)
C-u 付きで一つ、または複数のディレクトリを指定し、検索範囲を絞ることができる。
その際、ミニバッファを空欄にして RET を打鍵することで入力を終了する。この挙動は他のコマンドでも同じ。
M-x mdfind-dired-name (または mdfind-name-dired)
Mac OS X 10.5 以上が必要。 mdfind -name と同じ。ファイル名で検索する。
M-x mdfind-dired-interpret
Mac OS X 10.5 以上が必要。 mdfind -interpret と同じ。Spotlight メニューに入力する書式がそのまま使える。
例えば kind:image date:"this week" と入力すると、今週(作成、更新、開いた)の画像を検索。
M-x mdfind-dired-smartfolder
スマートフォルダを開く。
M-x mdfind-dired-toggle-visibility
ファイルのディレクトリ部分を「表示 / 隠す」。
mdfind の検索結果はトップディレクトリからのパスであることが多いので、例えば長いパスを
Users/foo/bar/baz/qux/quux/corge/grault/garply/waldo/fred/plugh/xyzzy/thud.txt
このように短縮表示する。
.../thud.txt
デフォルトの「表示 / 隠す」の状態は変数 mdfind-dired-default-visible で設定する。



Spotlight の使い方についてはこれらのページを参照してください。

他に Spotlight FS でも似たようなことができます。

2011-03-26

Dired で Spotlight コメントの表示、編集、タグ付け

Mac OS X では Spotlight コメント (Finder コメント) にタグを付けてスマートフォルダでファイルの管理ができます。

Spotlight コメントは Finder の「情報を見る」から編集できますが、Emacs 使いなら Dired でマークして一括タグ追加、削除、等と楽がしたいものです。

そんな Elisp パッケージをグーグル検索しても見つからなかったので、自分で書いてみました。

spotlight-comment.el
https://gist.github.com/888153

動作条件

GNU Emacs 22 と 23。 Mac OS X 10.4 以上。

インストール

上の gist から raw をクリックして spotlight-comment.el をダウンロードする。
load-path の通った場所へ置き、以下を ~/.emacs.el か ~/.emacs.d/init.el に追加。

(require 'spotlight-comment)
(define-key dired-mode-map "\M-c" spotlight-comment-dired-prefix-map)

使い方

キーバインドは何でもいいのですが M-c を例に使えるコマンドを説明すると、

M-c y
Spotlight コメントを表示。 C-u 付きでキルリングにコピー。
M-c e
Spotlight コメントを編集。
M-c D
マークしたファイルの Spotlight コメントを削除。
M-c s
マークしたファイルの Spotlight コメントを上書き。
M-c a
マークしたファイルの Spotlight コメントにタグを追加。
M-c d
マークしたファイルの Spotlight コメントからタグを削除。
M-c m
Spotlight コメントにタグが含まれるファイルにマークを付ける。

その他

  • タグ入力する際には、 TAB での補完が効きます。
    補完候補はミニバッファの履歴と変数 spotlight-comment-user-tags に設定してあるタグです。
    空欄のまま RET でタグ入力が終了します。
  • タグの区切り文字は変数 spotlight-comment-separator で設定し、デフォルトでは ", " (カンマとスペース)。
  • Spotlight コメントは全て Finder によって AppleScript 経由で書き換えられます。
    関数 do-applescript を使っていないので X11版 Emacs や Cocoa Emacs の -nw 起動でも使えるはずです。
  • 設定したタグは Spotlight の検索欄から comment:MyTag で MyTag を持つファイルを表示できます。


動作確認: GNU Emacs 23 (Mac port), Mac OS X 10.6

2011-03-22

Emacs Mac port に追加されている機能

Emacs Mac port についてはこちら Emacs Mac port を使う 。

Emacs Mac port に追加されている機能ですが、パッチに含まれる README-mac に詳細が書いてあります。
ここではその一部をまとめてみました。

パッチのバージョン emacs-23.3-mac-1.9992 を元に書いています。

  • 変数 window-system の値は mac
  • Command-Control-D でカーソル位置の単語の意味を辞書で表示
  • AppleEvent に対応
    Emacs に設定してあるメーラーが開く。 QuickCursor も使えるらしい
    osascript -e 'tell application "Emacs" to open location "mailto:foo@example.com"'
    
  • Emacs がビジーな時は、タイトルバー右側のインジケータがグルグル回る
  • fullscreen フレイムパラメータが認識される
    (set-frame-parameter nil 'fullscreen 'fullboth) でメニューバーと Dock が消えてフルスクリーンに!
    こんなコマンドを作って手軽に切り替えられるようにしてます
    (defun my-toggle-fullscreen ()
      "Toggle fullscreen."
      (interactive)
      (if (eq (frame-parameter nil 'fullscreen) 'fullboth)
          (progn
            (set-frame-parameter nil 'fullscreen nil)
            (display-time-mode 0))
        (set-frame-parameter nil 'fullscreen 'fullboth)
        (display-time-mode 1)))
    
    (global-set-key "\C-cf" 'my-toggle-fullscreen)
    
  • sticky フレイムパラメータが認識される
    (set-frame-parameter nil 'sticky t) で Spaces で全てのスクリーンに表示されるようになる
  • 関数 system-move-file-to-trash が定義されている
    変数 delete-by-moving-to-trash に設定することで、 Emacs からファイルを消去する際にゴミ箱に移動するようになる
    (setq delete-by-moving-to-trash 'system-move-file-to-trash) としてしまうと一時ファイル等でゴミ箱が溢れるので、 Dired 等特定のコマンドでのみ有効にするのが良いかもしれない
    ;; Dired の x や D でゴミ箱に捨てる。Finder での「取り消し」「戻す」は不可。
    (when (fboundp 'system-move-file-to-trash)
      (defadvice dired-do-flagged-delete
        (around move-to-trash activate)
        "Use `system-move-file-to-trash'."
        (let ((delete-by-moving-to-trash 'system-move-file-to-trash))
          ad-do-it))
    
      (defadvice dired-do-delete
        (around move-to-trash activate)
        "Use `system-move-file-to-trash'."
        (let ((delete-by-moving-to-trash 'system-move-file-to-trash))
          ad-do-it)))
    
  • M-x menu-bar-open でメニューバーが開く (menu-bar-mode が non-nil の場合)
    (global-set-key "\M-`" 'menu-bar-open) ; tmm-menubar
    
  • mac-mouse-wheel-mode. 行単位のカクついたスクロールではなく、ピクセル単位の滑らかなスクロール
  • トラックパッドのジェスチャーを認識する。 magnify-up, magnify-down, rotate-left, rotate-right
    デフォルトではテキストスケールの変更と、フルスクリーンの切り替えに割り当てられている
  • システム環境設定 → アピアランス の「クリックされた場所にジャンプ」が Emacs でも有効
  • システム環境設定 → キーボード の「キーボードショートカット (キーボードと文字入力)」が Emacs でも有効。
    例えば ^F2 でメニューバーが開く。 ^F4 でウィンドウ切り替え等
  • 他のアプリで画像をコピーした場合、 yank-pop でその画像を挿入できる。(変数 yank-excluded-properties で display を除外してない場合に限る)
  • Mac OS X 10.6 以上で、メニューバーのヘルプの検索語入力欄から info ノードを検索可能
  • Mac OS X 10.6 以上で、他のアプリにて選択したテキストがファイルのパスならば、 Emacs で開くためのコンテキストメニューとサービスが追加される
  • ことえりで、かなキー2回連打でカーソル位置の単語を再変換する機能が Emacs でも有効
  • 関数 mac-convert-property-list の追加
    Mac OS X の plist を lisp 等に変換できる。 plutil や xml.el とかでも似たようなものは実装できそうですが
    使用例としてはこんな感じで
    (mac-convert-property-list
     (let ((coding-system-for-read 'no-conversion))
       (with-temp-buffer
         (insert-file-contents "~/Library/Preferences/.GlobalPreferences.plist")
         (buffer-string))))
    

他に、 SVG やマルチページ TIFF の表示、 関数 mac-file-alias-p の追加、 Option-Command-T で「文字ビューアを表示」、 Resolution independence, 等々。

あと、私の環境では lookup.el で辞書を引くスピードが Cocoa Emacs では異様に遅かったのですが、 Emacs Mac port では軽快に動きました。

その他の注意点

  • mac-allow-anti-aliasing は削除された
    システム環境設定 -> アピアランス で設定するか、Terminal から以下を実行
    defaults write "org.gnu.Emacs" AppleAntiAliasingThreshold 12
  • ことえりの半角英字モードで C-S-a (Shift を押しながらの C-a) が効かなくなることがある。再現性はいまいち

do-applescript 関数について

  • Emacs Mac port の do-applescript は Carbon Emacs のそれと挙動は同じで、数点注意が必要です
    • do-applescript へ渡す文字列、返す文字列は変数 mac-system-coding-system でエンコード、デコードする必要がある
    • 変数 mac-system-coding-system は端末から Emacs を -nw 起動した時には初期化されていない
    • バックスラッシュは全て \200 (0x80) に置き換えられるので変換が必要
    • do-applescript が返す文字列はダブルクオートで囲まれているので、除去する必要がある
  • Cocoa Emacs の do-applescript (ns-do-applescript) は上記の面倒は無いのですが、端末で起動した時には do-applescript 関数は使えません
  • X11 用にビルドした Emacs では do-applescript は恐らく使えません
  • 外部コマンドの osascript を使う場合次の利点があります
    • Emacs Mac port, Carbon Emacs に特有の面倒が無い
    • 端末からの -nw 起動でも X11 版でも AppleScript を使える
    • on run argv で引数渡しができる
    • スクリプトの実行が失敗したかどうかが call-process の返り値でわかる

上記の理由から当ブログで紹介している Dired 関連の tips では do-applescript は使わず osascript を使っています

Emacs Mac port を使う

Emacs Mac port とは

Carbon Emacs (GNU Emacs 22) をベースとして、 GUI 部分に Cocoa API を取り入れ GNU Emacs 23 に対応させたものです。64bit 版もビルドできます。

Carbon Emacs のメインテナーをされていた YAMAMOTO Mitsuharu 氏によってパッチという形で提供されています。
パッチはここで入手できます。
ftp://ftp.math.s.chiba-u.ac.jp/emacs/

Cocoa Emacs (GNU Emacs 23 を –with-ns でビルドしたもの) と比べ、色々と機能が追加されています。
詳しくはパッチに同梱されている README-mac に書いてあります。
Emacs Mac port に追加されている機能 にもまとめてみました。

Emacs Mac port という呼称が適切なのか自信はないですが、 README-mac やソースでは "Mac port", "GNU Emacs Mac port" という名前が使われているので、当ブログでは Emacs Mac port で統一しました。

それにしても、 Mac port と MacPorts が似ていてウェブ検索での情報収集がしにくいです。

Emacs Mac port のインストール

詳しい手順はパッチに含まれる README-mac に載っています。
以下は 2011年3月現在の Emacs 23.3 をビルドする手順です。(Xcode が必要です)

  1. http://www.gnu.org/prep/ftp.html の最寄りのサーバから emacs-23.3.tar.bz2 を落とす。
  2. ftp://ftp.math.s.chiba-u.ac.jp/emacs/ から emacs-23.3-mac-1.9992.tar.gz を落とす。 1.9992 の部分は最新のバージョンで。
  3. ターミナルで
    tar jxf emacs-23.3.tar.bz2
    tar zxf emacs-23.3-mac-1.9992.tar.gz
    cd emacs-23.3
    patch -p0 < ../emacs-23.3-mac-1.9992/patch-mac
    cp -r ../emacs-23.3-mac-1.9992/mac .
    cp ../emacs-23.3-mac-1.9992/src/* ./src/
    cp ../emacs-23.3-mac-1.9992/lisp/term/mac-win.el ./lisp/term/
    ./configure --with-mac --without-x
    make
    sudo make install
    mv ./mac/Emacs.app /Applications/
    

    configure の --prefix オプションによっては sudo make install の部分は make install でも可。
    Cocoa Emacs とは違い、 self-contained ではないので、 --prefix を指定しないかぎり /usr/local 以下にインストールされます。

Emacs Mac port の設定

文字コードの設定

(set-language-environment 'Japanese)
(prefer-coding-system 'utf-8)
;; クリップボードの文字コード
(set-selection-coding-system 'utf-8)
;; 端末の文字コード
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
;; ファイル名の文字コード
(require 'ucs-normalize)
(set-file-name-coding-system 'utf-8-hfs)

Emacs Mac port の場合、クリップボード用の文字コード selection-coding-system がシステムのデフォルト言語で初期化されます。
日本語ならば japanese-shift-jis 。上の例では utf-8 にしてますが、 japanese-shift-jis でも問題は無いです。
ただ、これを japanese-shift-jis 以外の Shift_JIS (例えば sjis, sjis-mac 等) にすると、バックスラッシュが半角の円記号に化けたりと不具合が出ます。関数 mac-string-to-pasteboard-string でその辺りの処理をしています。

フォントの設定

基本的には Cocoa Emacs の設定の仕方と同じです。
Emacs Mac port は Carbon Emacs がベースですが、 carbon-font.el は使えません。

http://macemacsjp.sourceforge.jp/index.php?MacFontSetting より引用

(create-fontset-from-ascii-font "Menlo-14:weight=normal:slant=normal" nil "menlokakugo")
(set-fontset-font "fontset-menlokakugo" 'unicode (font-spec :family "Hiragino Kaku Gothic ProN" ) nil 'append)
(add-to-list 'default-frame-alist '(font . "fontset-menlokakugo"))
(setq face-font-rescale-alist '((".*Hiragino.*" . 1.2) (".*Menlo.*" . 1.0)))
  • アンチエイリアスに関して
    Carbon Emacs にあった変数 mac-allow-anti-aliasing は削除されています。
    システム環境設定のアピアランスで設定するか、Terminal から defaults で設定します。
    defaults write "org.gnu.Emacs" AppleAntiAliasingThreshold 12
    また、関数 font-spec の :antialias プロパティに nil か t をセットすることで、フォント毎の指定もできます。

  • フォント設定に関するバグ
    http://d.hatena.ne.jp/setoryohei/20110113
    3つの条件が重なると、バグが出るらしい。
    当方でも inhibit-startup-screen (inhibit-startup-message, inhibit-splash-screen) を t にしていると、□○△の記号類が半角サイズで表示される等、フォントが正しく設定されないのを確認しました。 Emacs Mac port でも再現性があります。

使えるフォントは *scratch* で

(insert (prin1-to-string (x-list-fonts "*")))

これを評価すれば全て表示されます。
Cocoa Emacs よりも太字が使えるフォントが増えていたりと、選択肢が多くなっているはずです。

  • Monaco 10
    Emacs Mac port で Monaco 10 に設定すると、斜体字は太字よりも太くなり、太字はぼやけてしまいます。
    アンチエイリアス無しで Carbon Emacs と同じようなフォント設定にするのは難しいようです。
    ちなみに Cocoa Emacs では Monaco の太字は使えません。
  • M+とIPAの合成フォント
    無料で使えます。 MigMix 1M, MigMix 2M, Migu 1M が等幅フォントで太字も含む。
    http://mix-mplus-ipa.sourceforge.jp/

その他の設定

Emacs Mac port のマウススクロールは非常に滑らかです。が、何らかの事情でマウススクロールを無効にしたい場合はこのようにします。

(add-hook 'window-setup-hook
          (lambda ()
            (when (fboundp 'mac-mouse-wheel-mode)
              (mac-mouse-wheel-mode 0))))

単に ~/.emacs.d/init.el に (mac-mouse-wheel-mode 0) と書き込んでも無効にはなりません。
詳しくは mac-win.el の after-init-hook に追加している個所を参照。

2011-03-03

Mac OS X 上の Emacs で M-x doctor に音声でしゃべらせる

Mac OS X には say というテキストを読み上げるコマンドがあります。
それを M-x doctor で利用すれば実際に声でしゃべってくれます。

;; M-x doctor
(defadvice doctor-read-print
  (after say activate)
  "Let the psychotherapist speak with audio voice."
  (start-process "say" nil "say" "-v" "Agnes"
                 (save-excursion
                   (buffer-substring-no-properties
                    (progn
                      (re-search-backward "\n\n" nil t 2)
                      (forward-char 2)
                      (point))
                    (progn
                      (re-search-forward "\n\n" nil t)
                      (forward-char -2)
                      (point))))))

doctor-mode のヘルプによると doctor の名前が Eliza (女性)なので、声は女性の Agnes を選んでみました。
声は他に Alex, Trinoids, Zarvox, Hysterical, Bad News, Good News 等があり、システム環境設定のスピーチで確認できます。

声を Hysterical にするとどちらが医者なのかわからなくなります。
リターン連打で何人もの医者から詰問を受けている気分になります。

いずれにせよ鬱陶しさ3割増といったところでしょうか。

2011-02-21

Mac OS X の拡張属性を消す removexattr

Mac OS X の拡張属性 (EA, Extended Attributes) はリソースフォーク、クリエータタイプ、不可視属性、等の HFS+ 固有のレガシーなものから、 com.apple.quarantine のような最近追加されたものまで色々あります。

拡張属性を確認する場合。
ls -l@ file
xattr file


普通は拡張属性を消す必要はないんですが、Windows の FAT32 のボリュームに Mac から拡張属性の付いたファイルをコピーすると、 file と ._file のように2つのファイルとしてコピーされます。できれば ._file のようなファイルは作りたくない。

消す場合は xattr コマンドで -d オプション。 com.apple.quarantine のような名前を指定する必要あり。
xattr -d com.apple.quarantine file

一つのファイルから全ての拡張属性を消すにはシェルスクリプトを書く必要があります。
しかしながら、 xattr (中身は python スクリプト) が妙に遅かったので、 C で書いたものが以下。

removexattr.c
/*
 * Require Mac OS X 10.4 or above.
 * man 2 listxattr
 * man 2 removexattr
 * gcc -O2 -o removexattr removexattr.c
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

#include <sys/xattr.h>

#define BUFSIZE 0x8000

int main(int argc, const char *argv[])
{
    int i, len;
    uint8_t *namebuf, *p;
    ssize_t size;

    if (argc <= 1) {
        fprintf(stderr,
                "Remove all extended attributes from given files or directories.\n"
                "Usage: %s [file ...]\n", argv[0]);
        exit(1);
    }

    namebuf = (uint8_t *)malloc(BUFSIZE);
    if (namebuf == NULL) {
        fprintf(stderr, "malloc() failed\n");
        exit(1);
    }

    for (i = 1; i < argc; i++) {
        size = listxattr(argv[i], namebuf, BUFSIZE, XATTR_NOFOLLOW);
        if (size <= 0)
            continue;

        p = namebuf;
        len = 0;
        while (len < size) {
            removexattr(argv[i], p, XATTR_NOFOLLOW);
            len = len + strlen(p) + 1;
            p = namebuf + len;
        }
    }

    free(namebuf);

    return 0;
}

コンパイルは (要Xcode)
gcc -O2 -o removexattr removexattr.c
使い方は
./removexattr file

find の -exec で指定ディレクトリ以下全てのファイル、フォルダの拡張属性を消すこともできますが、それはさすがに勇気がいります。

動作確認: Mac OS X 10.6

2011-02-19

Finder で最前面に表示されているフォルダを Emacs (Dired) で開く

Finder に切り替えて、フォルダを Dock の Emacs アイコンにドラッグ&ドロップすればいいのですが、もっと手軽にやりたい。

do-applescript 関数は互換性に関して面倒が多いので、 osascript を使います。

(defun my-dired-finder-window ()
  "Open the front most window of Finder in dired."
  (interactive)
  (let (file
        (script (concat
                 "tell application \"Finder\"\n"
                 "    if ((count Finder windows) >= 1) then\n"
                 "        get POSIX path of (target of window 1 as alias)\n"
                 "    else\n"
                 "        get POSIX path of (desktop as alias)\n"
                 "    end if\n"
                 "end tell\n")))
    (setq file (with-temp-buffer
                 (call-process "osascript" nil t nil "-e" script)
                 (buffer-substring-no-properties (point-min) (1- (point-max)))))
    (if (file-directory-p file)
        (dired file)
      (error "Not a directory: %s" file))))

(global-set-key "\C-cf" 'my-dired-finder-window)

動作確認: GNU Emacs 22, Mac OS X 10.6

2011-02-18

Dired からゴミ箱に捨てる、情報を見る、 Finder で表示

AppleScript でやるわけですが、 Emacs の do-applescript 関数は以下の3つの環境でのみ使用できるのを確認しています。X11 版は未確認です。

・ Cocoa Emacs の GUI 起動
・ Carbon Emacs の GUI 起動
・ Carbon Emacs の -nw 起動

3つそれぞれ微妙に違ったコードを書かなければならず面倒なので、 do-applescript は使わず外部コマンドの osascript を呼ぶ方法を紹介します。

キーバインドの例では、
M-DEL で Finder の「ゴミ箱に入れる」
M-i で Finder の「情報を見る」
M-r で Finder の「オリジナルを表示」
に割り当ててますが、適当に変えてください。 (特に M-r)

Dired で Finder の「ゴミ箱に入れる」
(defun my-dired-do-trash-1 (async &rest files)
  (let ((script
         (concat
          "on run argv\n"
          "    set itemArray to {}\n"
          "    repeat with i in argv\n"
          "        set itemArray to itemArray & (i as POSIX file as Unicode text)\n"
          "    end repeat\n"
          "    tell application \"Finder\"\n"
          "        delete itemArray\n"
          "    end tell\n"
          "end run\n")))
    (if async
        (apply 'start-process "osascript-trash" nil "osascript" "-e" script files)
      (apply 'call-process  "osascript" nil nil nil "-e" script files))))

;; Trash files
(defun my-dired-do-trash (&optional arg)
  "Trash the marked files.
If no files are marked or a specific numeric prefix arg is given,
the next ARG files are used.  Just \\[universal-argument] means the current file."
  (interactive "P")
  (let ((files (dired-get-marked-files nil arg))
        point)
    (message "Trashing...")
    ;; Position of the first mark
    (save-excursion
      (goto-char (point-min))
      (setq point (re-search-forward dired-re-mark nil t)))
    (unless point
      (setq point (point)))
    (apply 'my-dired-do-trash-1 nil files)
    (revert-buffer)
    ;; Restore the position
    (goto-char (point-min))
    (forward-line (line-number-at-pos point))
    (forward-line -1)
    (dired-move-to-filename)
    (message "Trashing...done")
    ;; Display the result
    (if (null (cdr files))
        (message "Trashed 1 item: %s" (file-name-nondirectory (car files)))
      (display-message-or-buffer
       (format "Trashed %d items:\n%s"
               (length files)
               (mapconcat 'file-name-nondirectory files "\n"))))))

(eval-after-load "dired"
  '(define-key dired-mode-map "\M-\C-?" 'my-dired-do-trash)) ; M-DEL, dired-unmark-all-files, use U or * ? RET

Dired で Finder の「情報を見る」
;; Get info
(defun my-dired-do-getinfo (&optional arg)
  "Show Finder's information window of the marked files.
If no files are marked or a specific numeric prefix arg is given,
the next ARG files are used.  Just \\[universal-argument] means the current file."
  (interactive "P")
  (let ((files (dired-get-marked-files nil arg))
        (script
         (concat
          "on run argv\n"
          "    tell application \"Finder\"\n"
          "        activate\n"
          "    end tell\n"
          "    repeat with i in argv\n"
          "        set i to (i as POSIX file as Unicode text)\n"
          "        tell application \"Finder\"\n"
          "            open information window of item i\n"
          "        end tell\n"
          "    end repeat\n"
          "end run\n")))
    (apply 'start-process "osascript-getinfo" nil "osascript" "-e" script files)))

(eval-after-load "dired"
  '(define-key dired-mode-map "\M-i" 'my-dired-do-getinfo)) ; tab-to-tab-stop

Dired で Finder の「オリジナルを表示」
;; Reveal in Finder
(defun my-dired-do-reveal (&optional arg)
  "Reveal the marked files in Finder.
If no files are marked or a specific numeric prefix arg is given,
the next ARG files are used.  Just \\[universal-argument] means the current file."
  (interactive "P")
  (let ((files (dired-get-marked-files nil arg))
        (script
         (concat
          "on run argv\n"
          "    set itemArray to {}\n"
          "    repeat with i in argv\n"
          "        set itemArray to itemArray & (i as POSIX file as Unicode text)\n"
          "    end repeat\n"
          "    tell application \"Finder\"\n"
          "        activate\n"
          "        reveal itemArray\n"
          "    end tell\n"
          "end run\n")))
    (apply 'start-process "osascript-reveal" nil "osascript" "-e" script files)))

(eval-after-load "dired"
  '(define-key dired-mode-map "\M-r" 'my-dired-do-reveal)) ; move-to-window-line

動作確認: GNU Emacs 22, Mac OS X 10.6

日本語や濁点の付いたファイル名に対しても動作しています。
手元の GNU Emacs 22 (Carbon) では「名\称\\未\\\設"定""フ"""ォルダ」のような悪魔的フォルダ名に対しては Dired がファイル名の取得に失敗します。これは Dired の問題です。
osascript の引数処理の関係で Mac OS X 10.4 以上が必要と思われます。


Terminal からゴミ箱に捨てる方法はこちら。 コマンドラインからゴミ箱に捨てるシェルスクリプト。

2011-02-17

コマンドラインからゴミ箱に捨てるシェルスクリプト

Mac OS X 用のゴミ箱スクリプトは検索すれば結構出てくるものの、どれもファイルを直接 ~/.Trash 等に移動するものが多いような気がする。
外付け HDD の場合はゴミ箱のパスが違うし、移動先に同じファイル名がある場合の処理とか、結構面倒くさい。

面倒くさいので全部 Finder に丸投げ、ということで AppleScript 経由でゴミ箱に捨てるスクリプトがこちら。

Finder で「ゴミ箱に入れる」
trash
#!/bin/sh

# Trash items.
# Usage: trash [files]

# Backslashes and doublequotes must be escaped.
# replace  \  -->  \\
# replace  "  -->  \"
CWD=`pwd | sed -E -e 's/\\\\/\\\\\\\\/g' -e 's/"/\\\\"/g'`

osascript - "$@" <<EOF
on run argv
    set itemArray to {}

    repeat with i in argv
        if first character of i is not "/" then
            set i to "$CWD" & "/" & i
        end if
        set itemArray to itemArray & (i as POSIX file as Unicode text)
    end repeat

    tell application "Finder"
        delete itemArray
    end tell
end run
EOF

動作確認:Mac OS X 10.6 (osascript の引数処理の関係で Mac OS X 10.4 以上が必要と思われます。)

使う場合、実行権限を付けて PATH の通った所へファイルを置いてください。
使い方の例: hoge.txt fuga.txt を捨てる
trash hoge.txt fuga.txt

AppleScript を使う利点としては、このスクリプトでゴミ箱に捨てた直後ならば、 Finder で「取り消す Cmd-Z」ができる。 Mac OS X 10.6 からはゴミ箱内の項目を「戻す」ことができるので、それにも対応している。欠点としては動作が遅い。


以下はおまけの Finder で「オリジナルを表示」と「情報を見る」のスクリプト。

Finder で「オリジナルを表示」
reveal
#!/bin/sh

# Reveal in Finder.
# Usage: reveal [files]

CWD=`pwd | sed -E -e 's/\\\\/\\\\\\\\/g' -e 's/"/\\\\"/g'`

osascript - "$@" <<EOF
on run argv
    set itemArray to {}

    repeat with i in argv
        if first character of i is not "/" then
            set i to "$CWD" & "/" & i
        end if
        set itemArray to itemArray & (i as POSIX file as Unicode text)
    end repeat

    tell application "Finder"
        activate
        reveal itemArray
    end tell
end run
EOF

Finder で「情報を見る」
getinfo
#!/bin/sh

# Show information window in Finder.
# Usage: getinfo [files]

CWD=`pwd | sed -E -e 's/\\\\/\\\\\\\\/g' -e 's/"/\\\\"/g'`

osascript - "$@" <<EOF
on run argv
    repeat with i in argv
        if first character of i is not "/" then
            set i to "$CWD" & "/" & i
        end if
        set i to (i as POSIX file as Unicode text)

        tell application "Finder"
            open information window of item i
        end tell
    end repeat

    tell application "Finder"
        activate
    end tell
end run
EOF

Emacs の Dired からゴミ箱に捨てる方法はこちら。 Dired からゴミ箱に捨てる、情報を見る、 Finder で表示。

2011-02-16

EmacsのバッファやDiredでカーソル位置のファイルを Quick Look

Mac OS X には qlmanage という便利なコマンドがあるのでそれを使う。

C-c y で Quick Look。もう一度 C-c y で、Quick Look を閉じる。
call-process を使って C-g で閉じるのもいいですが、やや反応が鈍いので下の例では start-process を使っています。

(defun my-quicklook-at-point ()
  "Preview a file at point with Quick Look."
  (interactive)
  (require 'ffap)
  (let ((url (ffap-url-at-point))
        (file (ffap-file-at-point))
        (process (get-process "qlmanage_ps")))
    (when url
      (if (string-match "\\`file://\\(.*\\)\\'" url)
          (setq file (match-string 1 url))
        (setq file nil)))
    (when (or (not (stringp file))
              (not (file-exists-p (setq file (expand-file-name file)))))
      (when process
        (kill-process process))
      (error "No file found"))
    (if process
        (kill-process process)
      (message "Quick Look: %s" file)
      (start-process "qlmanage_ps" nil "qlmanage" "-p" file))))

(global-set-key "\C-cy" 'my-quicklook-at-point)

Dired の設定。

(defun my-dired-do-quicklook ()
  "In dired, preview with Quick Look."
  (interactive)
  (let ((file (dired-get-filename))
        (process (get-process "qlmanage_ps")))
    (if process
        (kill-process process)
      (start-process "qlmanage_ps" nil "qlmanage" "-p" file))))

(eval-after-load "dired"
  '(define-key dired-mode-map "\C-cy" 'my-dired-do-quicklook))

キーバインドは適当に変えてください。

動作確認:GNU Emacs 22, Mac OS X 10.6

EmacsのバッファやDiredでカーソル位置のファイル(URL)をFinder(ウェブブラウザ)で開く

Finder でダブルクリックした時と同じ動作をさせたい場合、 Mac OS X には open という便利なコマンドがあるのでそれを使う。

;; カーソル位置のファイルや URL を open で開く
(defun my-open-at-point ()
  "Ask /usr/bin/open to open the thing at or before point."
  (interactive)
  (require 'ffap)
  (let ((file (or (ffap-url-at-point)
                  (ffap-file-at-point))))
    (unless (stringp file)
      (error "No file or URL found"))
    (when (file-exists-p (expand-file-name file))
      (setq file (expand-file-name file)))
    (message "Open: %s" file)
    (start-process "open_ps" nil "open" file)))

(global-set-key "\C-co" 'my-open-at-point)
;; double click
(global-set-key [double-mouse-1] 'my-open-at-point)
(global-set-key [double-down-mouse-1] 'ignore) ; mouse-drag-region

キーバインドは一例ですが、ダブルクリックにも割り当ててます。
以下のようなURLやファイルに対応します。

http://www.google.co.jp/
~/Library
/usr/include/stdio.h
#include <stdio.h>

注意点として、 (require 'hoge) のような文字列に対して実行すると、 hoge.el.gz というファイルが開き、 .gz が解凍されてしまう場合があります。この辺の挙動は y-or-n-p とか使って確認してから開く、という風に変えてもいいかもしれない。

以下 Dired の設定。

;; カーソル位置のファイルを open で開く
(defun my-dired-do-open (&optional arg)
  "In dired, invoke /usr/bin/open on the marked files.
If no files are marked or a specific numeric prefix arg is given,
the next ARG files are used.  Just \\[universal-argument] means the current file."
  (interactive "P")
  (let ((files (dired-get-marked-files nil arg)))
    (apply 'start-process "open_ps" nil "open" files)))

(eval-after-load "dired"
  '(define-key dired-mode-map "\C-co" 'my-dired-do-open))

動作確認: Mac OS X 10.6, GNU Emacs 22

2011-02-13

Mac OS X で Dired の日本語ファイル名の並び順がおかしい場合

Emacs の環境変数 LANG が UTF-8 の場合、 Dired の日本語ファイル名の並び順がおかしくなります。
これは Mac OS X の ls が LANG の値を見てランダムな並び順を出力するために起こります。
Emacs の設定ファイルに (setenv "LANG") や (setenv "LANG" "C") などと書けば正常な並び順になります。

普段は LANG=ja_JP.UTF-8 で、 Dired から ls を呼ぶ時だけ LANG=C にするには、以下のように設定します。

(setenv "LANG" "ja_JP.UTF-8")

(defadvice insert-directory
  (around setenv-LANG activate compile)
  "Set environment variable LANG to C."
  (let ((process-environment (copy-sequence process-environment)))
    (setenv "LANG" "C")
    ad-do-it))

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

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 でしています。