■ Windows Subsystem for Linux の emacs で利用できる設定


【お知らせ】


<2018/11/06 追記>
Windows 10 April 2018 Update 以降、マウントしたファイルサーバのエリアに cp -p でファイルをコピーすると、タイムスタンプが変更できないというエラーが発生するようになりました。これは、マウントオプションに uid=1000,gid=1000 を指定することで解決できることが分かりましたので、本説明を修正しました。

<2018/03/12 追記>
Cygwin版 はこちらを参照してください。

<2018/03/11 追記>
dired で開いているディレクトリの Windowsパス をクリップボードに取り込むキー設定を追加しました。

【本題】


Windows Subsystem for Linux で、Windowsパス と UNCパス を使えるようにするための設定です。

windows-path.el を参考として作っており、一部 windows-path.el のコードを含んでいますので、windows-path.el のライセンスに従いご利用ください。

1) 認証を必要とするネットワークボリュームを利用する場合は、予め以下の設定により認証情報を記憶させる。
※ ネットワークボリュームにアクセスした際に開く認証画面で、「資格情報を記憶する」にチェックを入れることでも登録できます。

2) 同じくネットワークボリュームを利用する場合は、以下のような /etc/fstab を設定し、マウントを行うようにする。
<for Windows 10 Fall Creators Update>
\\<ホスト名称>\<共有名>	/mnt/share1	drvfs	defaults	0 0
<for Windows 10 April 2018 Update or later>
\\<ホスト名称>\<共有名>	/mnt/share1	drvfs	defaults,noatime,uid=1000,gid=1000	0 0
※ Windows 10 April 2018 Update では、/etc/fstab があれば自動マウントするデフォルト設定となっています。Fall Creators Update までは、sudo mount -a が必要となります。
※ /etc/fstab の設定で、IPアドレスを含む UNC パスに対してのマウントポイントを指定する場合、「\\172」で始まる箇所などが8進数認識されてしまいます。この場合、2つ目の「\」を敢えて8進数の「\134」と記載することで対策可能です。
\\134172.16.0.1\<共有名>	/mnt/share1	drvfs	<オプション>	0 0

3) 以下の設定を行う。
(require 'cl-lib)

(defun set-drvfs-alist ()
  (interactive)
  (setq drvfs-alist
        (mapcar (lambda (x)
                  (setq x (replace-regexp-in-string "|/.\\."
                                                    (lambda (y)
                                                      (format "|//%o." (string-to-char (substring y 2 3))))
                                                    x))
                  (when (string-match "\\(.*\\)|\\(.*\\)" x)
                    (cons (match-string 1 x) (match-string 2 x))))
                (delete "" (split-string
                            (shell-command-to-string
                             "mount | grep 'type drvfs' | sed -r 's/(.*) on (.*) type drvfs .*/\\2\\|\\1/' | sed 's!\\\\!/!g'")
                            "\n")))))

(set-drvfs-alist)

(defconst windows-path-style-regexp "\\`\\(.*/\\)?\\([a-zA-Z]:\\\\.*\\|[a-zA-Z]:/.*\\|\\\\\\\\.*\\|//.*\\)")

(defun windows-path-convert-file-name (name)
  (setq name (replace-regexp-in-string windows-path-style-regexp "\\2" name t nil))
  (setq name (replace-regexp-in-string "\\\\" "/" name))
  (let ((case-fold-search t))
    (cl-loop for (mountpoint . source) in drvfs-alist
             if (string-match (concat "^" (regexp-quote source)) name)
             return (replace-match mountpoint t t name)
             finally return name)))

(defun windows-path-run-real-handler (operation args)
  "Run OPERATION with ARGS."
  (let ((inhibit-file-name-handlers
         (append '(windows-path-map-drive-hook-function)
                 (and (eq inhibit-file-name-operation operation)
                      inhibit-file-name-handlers)))
        (inhibit-file-name-operation operation))
    (apply operation args)))

(defun windows-path-map-drive-hook-function (operation name &rest args)
  "Run OPERATION on cygwin NAME with ARGS."
  (windows-path-run-real-handler
   operation
   (cons (windows-path-convert-file-name name)
         (if (stringp (car args))
             (cons (windows-path-convert-file-name (car args))
                   (cdr args))
           args))))

(add-to-list 'file-name-handler-alist
             (cons windows-path-style-regexp
                   'windows-path-map-drive-hook-function))
※ emacs を立ち上げた後に mount の追加登録を行った場合は set-drvfs-alist を再実行してください。M-x set-drvfs-alist で実行可能です。

4) find-file コマンド等で Windows パスや UNC パスを入力し、正しく変換されることを確認する。コピペでのパス入力をお薦めします。

5) 以下の設定を行う。Windows で作成したショートカットをシンボリックリンクの様に表示し、辿ることができるようになる。

6) dired で開いているディレクトリの Windows パスや UNC パス をクリップボードに取り込むには以下のキー設定を行う。
(require 'cl-lib)

(define-key dired-mode-map (kbd "C-c w")
  (lambda ()
    (interactive)
    (let ((name (file-truename (dired-current-directory)))
          (case-fold-search nil))
      (cl-loop for (mountpoint . source) in (reverse drvfs-alist)
               if (string-match (concat "^" (regexp-quote mountpoint)) name)
               return (progn
                        (setq name (replace-match source t t name))
                        (setq name (replace-regexp-in-string "/" "\\\\" name))
                        (shell-command-to-string
                         (format "echo -n %s | clip.exe" (shell-quote-argument name))))
               finally return (message "Windowsのパスには変換できません")))))


<変更履歴>
  • 2018/03/09 このページを作成した。
  • 2018/03/11 dired で開いているディレクトリの Windowsパス をクリップボードに取り込むキー設定を追加した。
  • 2018/03/22 コンピュータ名が IPアドレスの UNC パスを mount した際でも正常に動作するように対応した。
  • 2018/03/27 mapc 利用箇所を cl-loop の利用に置き換えた。
  • 2018/11/06 cp -p でコピーした際のタイムスタンプが変更できないエラーを解決するため、マウントオプションの見直しを行った。