【NTEmacsユーザー向け】find-fileの入力時に、ミニバッファにヤンクしたファイルパスの`\`が`/`に変わるようにした

検証version: emacs26
<br>


動機

チャットやメールなどに貼ってもらった共有フォルダ内のパスを使ってDiredを開きたいけど、
パス中のフォルダの区切りがバックスラッシュになっているので開けない。スラッシュに置換するのがめんどくさい。。。
しょうがなく、エクスプローラーを使っていた。



## 実現したいこと

流れ

1. Windowsのファイルパスをクリップボードにコピー
   - こんなやつ →    C:\フォルダ1\フォルダ1.1\ファイルA.txt
2. Emacsをアクティブにし、find-fileをインタラクティブに実行(C-x C-f)
3. クリップボードからkill-ringの先頭へ追加された1のファイルパスをyankする(C-y)

   ```
    Find file: C:/フォルダ1/フォルダ1.1/ファイルA.txt
 　ファイルA.txt
   ```
   


また、冒頭でも述べたように、使いたいファイルパスは共有フォルダのもの。
find-fileのミニバッファにヤンクしたとき以下のように変わってくれると、とても嬉しいですね。

クリップボードにコピーしたパス

- 10.35.83.2\フォルダ1\フォルダ1.1\

```
 Find file: U:/フォルダ1/フォルダ1.1/
./
../
ファイルA
ファイルB
ファイルC
``` 

※ 共有フォルダのあるサーバをネットワークドライブとして登録しておくと、Emacsから開けるようになります。上の例でUドライブに設定しています。

   
   

## 前提

1. OSのクリップボードとEmacsのkill-ringの同期を有効になっている

    確認方法
    変数`save-interprogram-paste-before-kill `を評価してください。
     
     出力がnilであれば無効になっているので、下のS式をロードパスの通ったEmacs-Lispのファイルに追加しましょう。

     ```elisp
     (setq save-interprogram-paste-before-kill t)
     ```

2. 対象の共有フォルダがネットワークドライブとして割り当てられている
 
    確認方法
    [こちら](https://pc-chain.com/windows10-network-drive/1690/)を参照してください。
    
3. cl.elが読み込まれている  
   以下が、ロードパスの通ったEmacs-Lispファイルのどこかに書いてあることを確認してください。

```elisp
(require 'cl)
```
Common Lispのcase関数を使います。

## 方法

以下をロードパスの通ったEmacs-Lispのファイルに追加してください。


```elisp

(defvar network-drives '(("u:" . "//10.35.83.2")
                         ("U:" . "//10.35.83.2")
             ;;↑の例のように、前提の2で確認、または新規登録したドライブをコンスセルとして書いておく
             ))

(add-hook 'minibuffer-inactive-mode-hook
          '(lambda ()
             (let ((clipbord (gui-selection-value)))
               (unless (null clipbord)
                 (setq kill-ring (cons clipbord kill-ring))
                 (setq kill-ring-yank-pointer kill-ring)))
             (unless (null kill-ring)
               (unless (null kill-ring-yank-pointer)
                 (let ((a (s-replace "\\" "/" (car kill-ring)))
                       (number 0))
                   (while (< number (length network-drives))
                     (case (string-match (cdr (nth number network-drives)) a)
                       (0
                        (setq kill-ring (cons (s-replace (cdr (nth number network-drives)) (car (nth number network-drives)) a) kill-ring ))
                        (setq number (length network-drives)))
                       (t
                        (setq kill-ring (cons a kill-ring))
                        (setq number (1+ number))
                        ))
                     (setq kill-ring-yank-pointer kill-ring)
                     ))))))

```
## 逆のケース

共有フォルダの中のファイルをEmacsで開いていて、そのパスを共有したいときもあるのではないでしょうか。

以下の関数を実行すると、クリップボードに現在のファイルのパスが入ります。
このとき、ファイルパスのスラッシュはバックスラッシュになり、ネットワークドライブの表示は登録したもとのパスに置換されます。

```elisp

(defun put-current-path-to-clipboard ()
  (interactive)
  (let ((file-path buffer-file-name)
        (dir-path default-directory))
    (defun convert-path-as-windows(path)
      (let ((a path)
            (number 0))
        (while (< number (length network-drives))
          (when (string-match (car (nth number network-drives)) a)
            (setq a (s-replace (car (nth number network-drives)) (cdr (nth number network-drives)) a))
            (setq number (length network-drives))
            )
          (setq number (1+ number)))
        (s-replace "/" "\\" a)))
    (cond (file-path
           (kill-new (convert-path-as-windows file-path))
           (message "(%s) --> clipboard" (convert-path-as-windows file-path)))
          (dir-path
           (kill-new (convert-path-as-windows dir-path))
           (message "(%s) --> clipboard" (convert-path-as-windows dir-path)))
          (t
           (error-message-string "Fail to get path name.")))))
```
上記関数を好みのキーバインドに設定するとより良いと思います。

## 参考

- [loop.el : ループでbreak/continue/returnを使えるようにする](http://emacs.rubikitch.com/loop/)
- [32.8.5 Low-Level Kill Ring](https://www.gnu.org/software/emacs/manual/html_node/elisp/Low_002dLevel-Kill-Ring.html)
- [Windows10 共有フォルダにネットワークドライブを割り当てる方法 ](https://pc-chain.com/windows10-network-drive/1690/)
- [開いているファイル/フォルダのパスをクリップボードに保存する](https://qiita.com/ShingoFukuyama/items/8f1d3342180d42ad9f78)