エクスプローラからWSLのVIMでファイルを開く方法

# お断り

以下の方法は本質的に下記サイトの内容をWindows10 1803アップデートに合わせて更新しつつ，パスに空白が含まれる場合に対応し，SendTo版を加えたものです．

- https://situsali.com/membuat-shortcut-open-vim-dari-wsl/ （インドネシア語）
  - [Google translateによる翻訳](https://translate.google.com/translate?sl=id&tl=en&js=y&prev=_t&hl=ja&ie=UTF-8&u=https%3A%2F%2Fsitusali.com%2Fmembuat-shortcut-open-vim-dari-wsl%2F&edit-text=)

また以下ではvimを例に説明していますが，vim固有の機能を使うわけではないので，ファイル名を引数として受け取る別のコマンド（emacsなど）にも応用できます．

# 目的
ちょっとしたテキストファイルの編集に，Windows Subsystem for Linux（以下WSL）のvim（≠gvim）を使いたい．しかもエクスプローラーから直接vimを起動したい．

#### 理由
* Windows版のvimをインストールしてSendToにでも入れておけば良いだけではある．しかしWSL側で作業するときは必ずvimを使うのでもともとvimは入っている．２つのvimをインストールするのは避けたい．
* WSL側のvimなら，Linuxで作業しているときと全く同じようにコマンドを呼べる（範囲指定して`:'<,'>:!sort|uniq`でソートして重複を削除するとか）．

# 方法１：レジストリを編集してコンテキストメニューに加える

以下の２点を実現するように，レジストリにキーを追加することで，コンテキストメニューからvimでファイルを開くことができるようにする．

1. bash.exeを起動して，その中でvimを起動する．
2. vimの引数にはエクスプローラで選択していたファイル名をWSL形式に変換して渡す．

まず`regedit`を起動して`HKEY_CLASSES_ROOT\*\shell`に新規キーとして`OpenWithVim`を作る（名前は適当でよい）．作成したら名前が`(規定)`な文字列値（`REG_SZ`）がその下にできているはずなので，値（データ）を`Open with Vim (&W)`にする．これもエクスプローラ上でファイルを右クリックした際に表示されるコンテキストメニュー上での項目名なので何でもよい．ただし末尾の`(&W)`はショートカットキーを決める文字列なので，好みのものに変更するとよい[^1]．

[^1]: たとえばvimの頭文字から`(&V)`としてもよい．しかし「以前のバージョンの復元」とキーが重複するため，`V`キーを押した後に`Enter`を押す手間が増える．

続けてキー`OpenWithVim`の下に新規キーとして`command`を作成し，`(規定)`文字列値のデータを

```
C:\Windows\System32\bash.exe -c "vim \"$(wslpath -a -u "%1")\""
```

にする．なお冒頭の参考サイトでは1803アップデート以前のWSLを想定して同様の処理を以下のように`sed`で行っている．

```
C:\Windows\System32\bash.exe -c "vim $(lower=$(echo "%1" | sed 's/\\/\//g' | sed 's/://') && echo /mnt/${lower,})"
```

以上を行うと，

1. ファイルを選択した状態でアプリケーションキー/メニューキーを押す（もしくはファイルを右クリックする）
2. コンテキストメニューが表示される
3. `W`キーを押す

という操作でvimが起動する．

参考までに，以下を`OpenWithVim.reg`など適当な名前のテキストファイルとして作成してダブルクリックすれば，上記の`regedit`によるキー追加を行うことができる．

```:OpenWithVim.reg
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\shell\OpenWithVim]
@="Open with Vim (&W)"

[HKEY_CLASSES_ROOT\*\shell\OpenWithVIM\command]
@="C:\\Windows\\System32\\bash.exe -c \"vim \\\"$(wslpath -a -u \"%1\")\\\"\""
```

# 方法２：「送る」メニューに加える

手順１の`command`と同じ内容を持つバッチファイルを作成して`SendTo`に配置すれば，コンテキストメニューの「送る」からvimで開くことができるようになる．

まず`Win+R`を押して「ファイル名を指定して実行」を開き，`shell:sendto`を実行すると`SendTo`フォルダが開く．このフォルダに下記の内容でバッチファイルを作る．ファイル名は適当でもよいが，先頭の文字がそのままショートカットキーになるので，使いやすいものを選ぶとよい．

```:vim-wsl.bat
@C:\Windows\System32\bash.exe -c "vim \"$(wslpath -a -u "%1")\""
```

以上を行うと，

1. ファイルを選択した状態でアプリケーションキー/メニューキーを押す（もしくはファイルを右クリックする）
2. コンテキストメニューが表示される
3. `N`キーで「送る」サブメニューが開く
4. `V`キーを押す

という操作でvimが起動する．

## 方法２’：複数ファイル対応版

バッチファイルを以下のように変更すると，複数のファイルを同時にタブで開くことができる．

```:vim-wsl.bat
@echo off
setlocal enabledelayedexpansion

set i=1
set WSLENV=Xa/u
set Xa=
for %%f in (%*) do (
    set X!i!=%%~f
    set WSLENV=!WSLENV!:X!i!/p
    set Xa=\"$X!i!\" !Xa!
    set /A i+=1
)

C:\Windows\System32\bash.exe -c "vim -p %Xa%"
```

行っていることは以下の通り．

1. バッチファイルの引数`%1`, `%2`, ...を，変数`X1`, `X2`, ...に入れる．ただしダブルクォートを除去する（`%%~f`の`~`による機能．これがないと`WSLENV`による変換に失敗する）．
2. `WSLENV`に`X1/p`, `X2/p`, ...を追加し，これらの変数がWSL側の環境変数として現れるように指示（`/p`はWindows側からWSL側へのパスの変換）．
3. vimを起動する際に，`WSLENV`を介して変換された環境変数`$X1`, `$X2`, ...を引数とする．

`wslpath`が複数のファイル名を一括変換してくれないので，`WSLENV`の`/p`によって実現している．また`WSLENV`の`/l`でも`PATH`変数の書式で一括変換ができるが，却って面倒な実装になりそうだったので断念．また`wslpath`をWSL側で複数回呼び出す方法も考えられるかもしれない．

# 参考
- https://situsali.com/membuat-shortcut-open-vim-dari-wsl/ （インドネシア語）
  - [Google translateによる翻訳](https://translate.google.com/translate?sl=id&tl=en&js=y&prev=_t&hl=ja&ie=UTF-8&u=https%3A%2F%2Fsitusali.com%2Fmembuat-shortcut-open-vim-dari-wsl%2F&edit-text=)
- [Windows 10のコマンドプロンプトからWSL上のLinuxコマンドを呼び出す（バージョン1803対応版）](http://www.atmarkit.co.jp/ait/articles/1805/24/news022.html)
- [【Windows】右クリックメニュー［送る］の活用方法、追加・設定方法（SendToディレクトリの場所一覧） | onocom](http://onocom.net/blog/windows-sendto-menu/)