悲しみの果て

悲しいお知らせですが、[前エントリ](https://qiita.com/astrorobot110/items/0526d5a39cd70901a4bf)は没となりました。

## 根本的な勘違い

そもそもなぜ巨大なだけのこんなスクリプトが出来上がってしまったのかを考える必要があります。

### プロジェクトリーダーの理解

1. netrw内のブックマークファイル(`.netrwbook`)はただのvimスクリプトなので、先にロードしておけば、netrwの変数 `g:netrw_bookmarklist` を使えるかもしれない
2. ノーマルモードの `gb` が空いていた
3. ディレクトリ関係を弄るのであればvim導入初期から使っていた`<Leader>v`から始まる設定ファイルへの移動マップもうまく組み込みたい
4. なんか `:split some/directory/` と `:Hexplore some/directory/` の挙動が違う気がする (すごく気になる)

というわけで、この辺の欲を一気にまとめるスクリプトを作ろうという発想に至ったわけです。

### 得られたサポート

そもそもじゃあこの差はなんなんだ？って話なんだけど…何の成果も得られませんでした。ただ `:Hexplore` を使うと既にあるnetrwのバッファ内でディレクトリ移動されて、 `:Rexplore` を使うまでウィンドウとして出てこない事があるので「これは何なんだろう」というところまでしかわかりませんでした。

### プログラマのコード

…はもう前のエントリで見てもらえばいいとして、どうにもやるべきことに対して労力が見合っていません。この状態から更に捻じ伏せようという気になれなくなったところで根本的に方法が間違っている事に気が付きました。

### 顧客が本当に必要だったもの

そもそもnetrwはどう使われたいのでしょうか？確かに `:Explorer` は現在のバッファの編集状態を見ていい感じにウィンドウを開くダンディなヤツですが、「もっとカジュアルに `:e some/directory/` で使ってもいいよ」と言ってくれているんです。じゃあわざわざ長いコマンドを使わずに `:e`, `:sp`, `:vs` でいいじゃないですか。"Small is beautiful" を忘れちゃダメっすよ…

## 実装された運用

```vim:dirz.vim
if !exists('g:netrw_bookmarklist')
	try
		execute printf("source %S/%S", g:netrw_home, '.netrwbook')
	catch /E121/
		execute printf("source %S/%S", split(&runtimepath, ',')[0], '.netrwbook')
	endtry
endif

let s:cmdDict = {
	\ 'e' : 'edit',
	\ 'e!' : 'edit!',
	\ 's' : 'split',
	\ 'v' : 'vsplit',
	\ 't' : 'tabe',
	\ 't!' : 'tabe'
	\ }
let s:cmdDict['s!'] = &splitbelow ? 'abo split' : 'bel split'
let s:cmdDict['v!'] = &splitright ? 'lefta vsplit' : 'rightb split'

function! dirz#open(...) abort
	let path = a:1
	let isBang = exists('a:2') ? a:2 : ''
	let drx = exists('a:3') ? tolower(a:3[0]) : ''

	if drx == ''
		if getbufinfo(bufname(''))[0]['changed']
			let drx = isBang == '!' ? 'v' : 's'
		else
			let drx = 'e'
		endif
		let isBang = ''
	endif

	execute printf("%s %S", s:cmdDict[drx.isBang], path)
endfunction

function! dirz#netrwBook(...) abort
	let index = exists('a:1') ? a:1 : 0
	let isBang = exists('a:2') ? a:2 : ''
	let drx = exists('a:3') ? a:3 : ''

	if index == 0
		let line = 1
		for bm in g:netrw_bookmarklist
			echo printf('%3d: %s', line, bm)
			let line += 1
		endfor

		call inputsave()
		let selected = input('番号と<Enter>を入力して下さい (空でキャンセル): ')
		call inputrestore()
	else
		let selected = index
	endif

	call dirz#open(g:netrw_bookmarklist[abs(selected)-1], isBang, drx)
endfunction

noremap <Plug>(dirz_netrwBookS) :<C-u>call dirz#netrwBook(v:count)<CR>
noremap <Plug>(dirz_netrwBookV) :<C-u>call dirz#netrwBook(v:count, '!')<CR>
noremap <Plug>(dirz_netrwBookT) :<C-u>call dirz#netrwBook(v:count, '', 't')<CR>

command! -bang Bookz call dirz#netrwBook('', '<bang>', '')
command! -bang SBookz call dirz#netrwBook('', '<bang>', 's')
command! -bang VBookz call dirz#netrwBook('', '<bang>', 'v')
command! -bang TBookz call dirz#netrwBook('', '<bang>', 't')
```

…どうしてこんな事になってしまったんだ。

### さておき

やっていることは基本的に一緒で、netrwのブックマークをノーマルモードからも使うためのものです。`dirz#netrwBook()` 関数の方で `g:netrw_bookmarklist` からパスを読み込んで、開き方の指定は汎用的に使える `dirz#open()` 関数に任せています。むしろ本体は `dirz#open()` に見えてきます。

### `dirz#open()` 関数

`:Explorer` のバッファの編集状況をチェックしていい具合にウィンドウ分割するダンディな部分はぜひ実装したいということで残しました。

#### モード

`dirz#oepn()` の第三引数のモードは大体こんな感じです。

| mode   | 名称           | bangなし挙動                            | bangあり挙動                             |
| ------ | -------------- | :-------------------------------------: | :--------------------------------------: |
| (なし) | ワイズモード   | バッファが保存されていなければ `:split` | バッファが保存されていなければ `:vsplit` |
| `s`    | 垂直分割モード | `:split`                                | `:split` と逆方向 (&splitbelowを参照)    |
| `v`    | 水平分割モード | `:vsplit`                               | `:vsplit` と逆方向 (&splitrightを参照)   |
| `t`    | タブモード     | `:tabe`                                 | `:tabe`                                  |
| `e`    | 通常モード     | `:edit`                                 | `:edit!`                                 |

## アナリストのデザイン

とりあえず汎用に使える関数にしてしまったので、netrwに入れるには適してない[^1]ブックマークを別なスクリプトから定義して使ってもいいかなと思ってたんですけど…けど、なんですよ。このスクリプト作成前のvimのコンフィグへのリマップ「群」が「選んで」「開く」という形になっていたのは良くないんじゃないのか？という自問自答が始まってしまいました。一つの動作で一つづつ操作を定義すれば、マトリクスを書くためにすべての状態を書く必要はないわけで…というわけで現在手近にアクセスしたいファイルのパスはコマンドモードの短縮入力にしてみました。とはいえ打鍵数は多いので頑張り過ぎかなとも思っているので…弱ったなまたスクリプトが増えるぞ…？

[^1]: netrwのブックマークは追加するとリストの最初の要素に入るのでカウントがズレる。