プログラム系統備忘録ブログ

記事中のコードは自己責任の下でご自由にどうぞ。

Emacsで開いているバッファのファイルを選択した状態でExplorerを開く

しばしば、Emacsで開いているバッファのファイルをExplorerで開きたくなります。
というより、ディレクトリのショートカット作ってそれにアクセスするよりも、recentf+anythingでファイルを開いてコマンド打ったほうが手早く幅広く出来そうです。

この記事ではその動作をするEmacsLispを紹介します。
この記事に記載したコードは、gnupackのEmacsにてWindowsXP及びWindows7で確認しました。
なお、この記事では文字コードの取り扱いは省略しています。変換が必要な場合はencode-coding-stringをご利用ください。

start-processから直接explorerを呼び出す(不具合あり)

しばらくはこれを使っていたのですが、最近になって「半角スペースを含むパス」が開けない(必ずMyDocumentsが開かれる)ことが分かりました。
なおこのコードでapplyを経由して呼び出している理由は謎です。

(defun explorer (&optional path)
  "引数があればそのパスの、引数が省略されていれば現在のバッファのファイルを、explorerで開きます。"
  (interactive)
  (setq path (expand-file-name (or path (buffer-file-name))))
  (cond
    ((not (file-exists-p path))
     (message "path %s isn't exist" path))
    (t
     (let ((dos-path (replace-regexp-in-string "/" "\\\\" path)))
       (apply (function start-process)
              "explorer" nil "explorer.exe" (list (concat "/select," dos-path)))))))

start-processでスクリプトを経由する(一手間必要)

dired で ファイルを選択状態でエクスプローラを起動 - l1o0の日記にPerlを経由する方法があったのでそれで試してみました。
この方法であると、日本語を含むパスも半角スペースを含むパスも正しく開けました。
ただし、私の環境だとPerlファイルをstart-processするところでPermission deniedとなったためEmacsLisp中に直接記載しています。

(defun explorer (&optional path)
  "引数があればそのパスの、引数が省略されていれば現在のバッファのファイルを、explorerで開きます。"
  (interactive)
  (setq path (expand-file-name (or path (buffer-file-name))))
  (cond
    ((not (file-exists-p path))
     (message "path %s isn't exist" path))
    (t
     (start-process "open explorer" nil
                    "perl" ;起動するコマンド
                    "-E" ;次の引数をスクリプトとして解釈
"my $file = shift;
$file =~ s#/#\\\\#g; # パスのデリミタはバックスラッシュ固定、elispの文字列中なのでバクスラの数二倍
system 'C:/windows/explorer.exe', '/select,', $file; # フルパスを書かないと見つからなかった
"
                    path)))) ;開きたいファイルを指定

w32-shell-executeを使う(お勧め)

この方法でも、日本語を含むパスや半角スペースを含むパスでも正しく開けました。
EmacsLispの範囲で完結しているため、これが一番好みです。

(defun explorer (&optional path)
  "引数があればそのパスの、引数が省略されていれば現在のバッファのファイルを、explorerで開きます。"
  (interactive)
  (setq path (expand-file-name (or path (buffer-file-name))))
  (cond
    ((not (file-exists-p path))
     (message "path %s isn't exist" path))
    (t
     (let ((dos-path (replace-regexp-in-string "/" "\\\\" path)))
       (w32-shell-execute "open" "explorer.exe" (concat "/select," dos-path))))))

おまけ

diredで開いているディテクトリを選択した状態でExplorerを開くには、次の関数をdired-mode-mapに割り当てておくと簡単です。

(defun dired-exec-explorer ()
  "In dired, execute Explorer"
  (interactive)
  (explorer (dired-current-directory)))