【Vim】defx.nvimで高速でリッチなファイラを実現する(アイコン、git status表示)



#defx.nvim とは

<img width="1006" alt="スクリーンショット 2020-04-25 21.48.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78906/f96fb182-615b-aaa3-29e7-c8734efdf7a2.png">

画像の左の部分が[defx.nvim](https://github.com/Shougo/defx.nvim)です。

defxは、かの有名な暗黒美夢王[Shougo](https://twitter.com/ShougoMatsu)さんの作成されたdark powerdなvimのファイラ(ファイルエクスプローラ)です。

vimのファイラと言うと、他にもNERDTreeや、同じくShougoさん作のVimFilerなどをお使いの方もいると思います。
体感ですが、defxは他のファイラに比べてかなり動作が早いです。また拡張性もあります。
**開発の終了したVimFilerやもっさりしたNERDTreeを卒業し、暗黒の力を手にしましょう。**

<details><summary>環境</summary>
macOS Catalina
iTerm2
NVIM v0.5.0-ef0398f
</details>

#NeoVimをインストール

defx.nvimの動作には`NeoVim`または`Vim8.1+` と`Python3.6.1+`が必要です。僕は[NeoVim](https://github.com/neovim/neovim)を強くお勧めします。この機会に移行しましょう。2020年だし。
brewでNeoVimをインストールしただけだとPython3はついてこないので、以下の方法でインストールします。

```terminal:console
sudo pip3 install neovim
brew tap neovim/neovim
brew install --HEAD neovim
```
vimを開いて`:echo has("python3")`と打ち込み、`1`が返ってきたらOKです。また、deopleteを問題なく使えている方は大丈夫です。

#defx.nvimをインストール


* dein.vim

```vimscript:init.vim
call dein#add('Shougo/defx.nvim')
if !has('nvim')
  call dein#add('roxma/nvim-yarp')
  call dein#add('roxma/vim-hug-neovim-rpc')
endif
```

* vim-plug

```
if has('nvim')
  Plug 'Shougo/defx.nvim', { 'do': ':UpdateRemotePlugins' }
else
  Plug 'Shougo/defx.nvim'
  Plug 'roxma/nvim-yarp'
  Plug 'roxma/vim-hug-neovim-rpc'
endif
```

defxはVimFilerとは違い、deinte.nvimに依存しないので、defx単体のみのインストールで大丈夫です。

([dein.vim](https://github.com/Shougo/dein.vim)は非常に優れたプラグインマネージャです。まだ導入してない人はこの機会に導入を検討してはいかがでしょうか)

# 一般の設定

### キーバインド

まず、defxにはデフォルトのキーバインドというものが存在しません。ファイルを開くアクションにも、ディレクトリを移動するアクションも全て自分で設定する必要があります。
とは言っても、[公式のドキュメント](https://github.com/Shougo/defx.nvim/blob/master/doc/defx.txt#L673)にお勧めの設定的なやつがのってるので、ほとんどそれをコピペすれば済みます。

```vimscript:init.vim
autocmd FileType defx call s:defx_my_settings()

function! s:defx_my_settings() abort
  nnoremap <silent><buffer><expr> <CR>
   \ defx#do_action('drop')
  nnoremap <silent><buffer><expr> c
  \ defx#do_action('copy')
  nnoremap <silent><buffer><expr> m
  \ defx#do_action('move')
  nnoremap <silent><buffer><expr> p
  \ defx#do_action('paste')
  nnoremap <silent><buffer><expr> l
  \ defx#do_action('drop')
  nnoremap <silent><buffer><expr> t
  \ defx#do_action('open','tabnew')
  nnoremap <silent><buffer><expr> E
  \ defx#do_action('drop', 'vsplit')
  nnoremap <silent><buffer><expr> P
  \ defx#do_action('drop', 'pedit')
  nnoremap <silent><buffer><expr> o
  \ defx#do_action('open_or_close_tree')
  nnoremap <silent><buffer><expr> K
  \ defx#do_action('new_directory')
  nnoremap <silent><buffer><expr> N
  \ defx#do_action('new_file')
  nnoremap <silent><buffer><expr> M
  \ defx#do_action('new_multiple_files')
  nnoremap <silent><buffer><expr> C
  \ defx#do_action('toggle_columns',
  \                'mark:indent:icon:filename:type:size:time')
  nnoremap <silent><buffer><expr> S
  \ defx#do_action('toggle_sort', 'time')
  nnoremap <silent><buffer><expr> d
  \ defx#do_action('remove')
  nnoremap <silent><buffer><expr> r
  \ defx#do_action('rename')
  nnoremap <silent><buffer><expr> !
  \ defx#do_action('execute_command')
  nnoremap <silent><buffer><expr> x
  \ defx#do_action('execute_system')
  nnoremap <silent><buffer><expr> yy
  \ defx#do_action('yank_path')
  nnoremap <silent><buffer><expr> .
  \ defx#do_action('toggle_ignored_files')
  nnoremap <silent><buffer><expr> ;
  \ defx#do_action('repeat')
  nnoremap <silent><buffer><expr> h
  \ defx#do_action('cd', ['..'])
  nnoremap <silent><buffer><expr> ~
  \ defx#do_action('cd')
  nnoremap <silent><buffer><expr> q
  \ defx#do_action('quit')
  nnoremap <silent><buffer><expr> <Space>
  \ defx#do_action('toggle_select') . 'j'
  nnoremap <silent><buffer><expr> *
  \ defx#do_action('toggle_select_all')
  nnoremap <silent><buffer><expr> j
  \ line('.') == line('$') ? 'gg' : 'j'
  nnoremap <silent><buffer><expr> k
  \ line('.') == 1 ? 'G' : 'k'
  nnoremap <silent><buffer><expr> <C-l>
  \ defx#do_action('redraw')
  nnoremap <silent><buffer><expr> <C-g>
  \ defx#do_action('print')
  nnoremap <silent><buffer><expr> cd
  \ defx#do_action('change_vim_cwd')
endfunction
```

これには若干僕のオリジナルが入っています。

* 僕は、**常に作業画面の左側にファイルをツリー表示して置く使い方**なので、ファイルを開くときのアクションが`open`ではなく`drop`になっています。
* 公式ドキュメントには載っていませんが、`defx#do_action('open','tabnew')`で、選択したファイルを新しいタブで開くことができます。僕はこれを`t`にバインドしました。

各アクションの意味は[ここ](https://github.com/Shougo/defx.nvim/blob/master/doc/defx.txt#L183)

### vim起動時に起動、\<Leader>fで起動
VimFilerを使っていたときには、vim起動時に自動的にVimFilerを左側に開き、また`<Leader>f`でも開くようにしていたので、同じように設定したいと思います。
このようなキーバインドは各自でお好みで設定してください。


```vimscript:init.vim
autocmd VimEnter * execute 'Defx'
nnoremap <silent> <Leader>f :<C-u> Defx <CR>
```

###起動時のレイアウトや設定

defx起動時の設定をしています。各自お好みで。

```vimscript:init.vim
call defx#custom#option('_', {
      \ 'winwidth': 40,
      \ 'split': 'vertical',
      \ 'direction': 'topleft',
      \ 'show_ignored_files': 1,
      \ 'buffer_name': 'exlorer',
      \ 'toggle': 1,
      \ 'resume': 1,
      \ })

```


|option|説明|
|:-----|---|
|winwidth|ファイルエクスプローラの幅。30~50がお勧め|
|split|ウィンドウの出し方。'floating'などもある。neovimの強さを実感できるのでやってみてほしい|
|direction|ファイルエクスプローラの位置。`topleft` or `botright` |
|show_ignored_files|いわゆるdotfilesを表示するかどうか。`1`で表示。 |
|buffer_name|バッファの名前|
|toggle|`1`にすれば、`:Defx`で、defxを開くだけでなく、閉じることもできるようになります。|
|resume|`1`にすれば、一度defxを閉じてからもう一度開いても、閉じる前の状態から始めることができます。|

###自動的に更新

defxのアクションでファイルを作成した時などは、もちろん即時にその変更が画面に反映されます。しかし、以下の設定を加えることで、vimの外でファイルを削除したりした時なども反映されるようになります。

```vimscript:init.vim
autocmd BufWritePost * call defx#redraw()
autocmd BufEnter * call defx#redraw()
```

autocmdを使って、バッファ保存時、またはバッファ移動時に再描画`redraw()`をフックしています。ほんとはn秒に一回更新とかがいいけど...できるの？教えて誰か

#アイコン

ここまでで、うまくいってればこんな感じになってると思います。(色は個人の設定によると思うので気にしないで)
<img width="400" alt="スクリーンショット 2020-04-26 0.59.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78906/c1db96cb-e891-edaf-409b-c061fa0f8da9.png">

十分かっこいいですが、さらに、IDEのようにファイル名の横にファイル種別ごとにアイコンを出すことができます。

##フォントをインストール
Nerd Fontをbrewでインストールします。これはmacOS向けのインストールの方法です。他のOSの方は[こちら](https://github.com/ryanoasis/nerd-fonts#font-installation)を参照されたし。

```terminal:console
 brew tap homebrew/cask-fonts
 brew install font-hack-nerd-font --cask
```

##Terminal側の設定

**今更ですが、ターミナルはiTerm2の使用をお勧めします。iTerm2ではASCII FontとNon-ASCII Fontを別々で設定できるからです。　**
Non-ASCII Fontで、先ほどダウンロードしたフォントを選択しましょう。

<img width="1004" alt="スクリーンショット 2020-04-26 1.20.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78906/0d507f0e-f9a9-c1eb-2bb4-6faabf2daf7f.png">


macデフォルトのターミナルをどうしても使いたい方は、Fontをダウンロードしたものに変更してください。

##defx-iconsとvim-deviconsをインストール
[defx-icons](https://github.com/kristijanhusak/defx-icons)と[vim-devicons](https://github.com/ryanoasis/vim-devicons)の2つのプラグインが必要です。

* dein

```vim

call dein#add('ryanoasis/vim-devicons')
call dein#add('kristijanhusak/defx-icons')
```

* dein (toml)

```toml

[[plugins]]
repo = 'ryanoasis/vim-devicons'

[[plugins]]
repo = 'kristijanhusak/defx-icons'
```
* vim-plug

```vimscript

Plug 'kristijanhusak/defx-icons'
Plug 'ryanoasis/vim-devicons'
```

インストールを実行することを忘れないでください:raised_hand:

##init.vimを調整
先ほどの`call defx#custom#option('_', {....`のブロックに,
`columns`のオプションを追加します。
このオプションを設定することで、defxのカラムに表示される情報を取捨選択したり、その順番を変更したりすことができます。今回は、左から、インデント(ディレクトリの階層を表現する)、ファイル種別ごとのアイコン、ファイル名、選択マークの順に表示することにします。


```vimscript:init.vim
call defx#custom#option('_', {
  \ 'winwidth': 40,
  \ 'split': 'vertical',
  \ 'direction': 'topleft',
  \ 'show_ignored_files': 1,
  \ 'buffer_name': 'exproler',
  \ 'toggle': 1,
  \ 'resume': 1,
  \ 'columns': 'indent:icons:filename:mark',
  \ })
```

これでアイコンの設定が完了しました！vimを再起動すると、このように表示されているでしょうか？アイコンがかわいくて良い感じですね:baby:

<img width="402" alt="スクリーンショット 2020-04-29 1.43.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78906/6d220e34-8ae7-16cd-b13a-e94e53a16337.png">


#gitのstatusを表示

gitで管理されているファイルのステータスをファイルツリーに表示するのは多くのIDEでは標準的な機能です。defxでもプラグインを用いれば可能です。

##defx-gitをインストール
gitのステータスを表示するには、プラグイン[defx-git](https://github.com/kristijanhusak/defx-git)をインストールします。

* dein

```vim

call dein#add('kristijanhusak/git')
```

* dein (toml)

```toml

[[plugins]]
repo = 'kristijanhusak/defx-git'
```
* vim-plug

```vimscript

Plug 'kristijanhusak/defx-git'

```
インストールを実行することを忘れないでください:raised_hand:


##init.vimを調整
先ほどと同様に、`call defx#custom#option('_', {....`のブロックをいじります。`columns`の、`indent`と`icons`の間に`git`を追加します。


```vimscript:init.vim
call defx#custom#option('_', {
  \ 'winwidth': 40,
  \ 'split': 'vertical',
  \ 'direction': 'topleft',
  \ 'show_ignored_files': 1,
  \ 'buffer_name': 'exproler',
  \ 'toggle': 1,
  \ 'resume': 1,
  \ 'columns': 'indent:git:icons:filename:mark',
  \ })
```

次に、gitのステータスごとに表示されるアイコンを設定します。これもNERDフォントで指定できたらカッコいいですね。方法を知りたい。


```vim:init.vim
call defx#custom#column('git', 'indicators', {
  \ 'Modified'  : '✹',
  \ 'Staged'    : '✚',
  \ 'Untracked' : '✭',
  \ 'Renamed'   : '➜',
  \ 'Unmerged'  : '═',
  \ 'Ignored'   : '☒',
  \ 'Deleted'   : '✖',
  \ 'Unknown'   : '?'
  \ })

```

これで全ての設定が完了しました。vimを再起動し、gitで管理されているディレクトリに入って表示を確認してみます。このように表示されているでしょうか？

<img width="500" alt="スクリーンショット 2020-04-29 2.04.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78906/2c1f422d-4446-c5b0-c627-237d570e4800.png">

gitのアイコンが新しく表示されているのがわかると思います。いい感じですね！！

#詞

+ カスタマイズ性がすごいので、[公式リファレンス](https://github.com/Shougo/defx.nvim/blob/f962b9908f48f823b817b7fd61ce9d706bbb41fd/doc/defx.txt)などを読み込めばもっといろんなことができるようになると思います。
+ めっちゃはやい！けど、アイコンを表示するとちょっと遅くなる...気がする？
+ NERDフォント、普通にいいかんじなので、自分でいろんなところに使いたい。けど表示する方法がわかんない。教えて誰か...
+ Shougoさん、いつも最高のプラグインをありがとうございます。
+ 間違っている情報や古くなった情報などがあればご指摘お願いします。