How to create a buffer with customized behavior? / How to create a buffer that acts like a TUI?
What vimscript magic allows one to create buffers with highly customized behavior, that effectively act like a TUI, such as those presented by NerdTree or other file explorer plugins and Gundo or o...
How to create a buffer with customized behavior? / How to create a buffer that acts like a TUI? favicon https://vi.stackexchange.com/questions/14832/how-to-create-a-buffer-with-customized-behavior-how-to-create-a-buffer-that-a
How to create a buffer with customized behavior? / How to create a buffer that acts like a TUI?

BufferList読んでみる

273行

この量なら読める。

インクルードガード

if exists('g:BufferListLoaded')
finish
endif
let g:BufferListLoaded = 1

初期値決め

" vimrcで先に値を決められるようにしている?
" vimrc より plugin の方が後に実行されるからか?
if !exists('g:BufferListWidth')
let g:BufferListWidth = 20
endif
if !exists('g:BufferListMaxWidth')
let g:BufferListMaxWidth = 40
endif

BufferList関数

__BUFFERLIST__ という Buffer を専用のバッファとして扱う。

" toggled the buffer list on/off
function! BufferList()
" if we get called and the list is open --> close it
if bufexists(bufnr("__BUFFERLIST__"))
" 既に開いていたら閉じる
exec ':' . bufnr("__BUFFERLIST__") . 'bwipeout'
return
endif

bufnr でバッファ名からバッファ番号を得て、bufexists で存在を確認する。 bufnr には特別な名前を指定出来て以下のような効果があるようだ。

let l:bufcount = bufnr('$')
let l:activebuf = bufnr('')

バッファを作る

作ったバッファがアクティブになり、以降の操作対象になる。

" now, create the buffer & set it up
exec 'silent! ' . l:width . 'vne __BUFFERLIST__'

色決め

" set up syntax highlighting
if has("syntax")
syn clear
syn match BufferNormal / .*/
syn match BufferSelected /> .*/hs=s+1
hi def BufferNormal ctermfg=black ctermbg=white
hi def BufferSelected ctermfg=white ctermbg=black
endif

Buffer構築

setlocal nomodifiable で編集不可に

setlocal modifiable
if l:displayedbufs > 0
" input the buffer list, delete the trailing newline, & fill with blank lines
put! =l:buflist
" is there any way to NOT delete into a register? bummer...
"norm Gdd$
norm GkJ
while winheight(0) > line(".")
put =l:fill
endwhile
else
let l:i = 0 | while l:i < winheight(0) | let l:i = l:i + 1
put! =l:fill
endwhile
norm 0
endif
setlocal nomodifiable

操作を設定

バッファローカルに map を設定する。 map がキーボード・マウス入力へのコールバック設定になっているのか。なるほど。

" set up the keymap
noremap <silent> <buffer> <CR> :call LoadBuffer()<CR>
map <silent> <buffer> q :bwipeout<CR>
map <silent> <buffer> j :call BufferListMove("down")<CR>
map <silent> <buffer> k :call BufferListMove("up")<CR>
map <silent> <buffer> d :call BufferListDeleteBuffer()<CR>
map <silent> <buffer> <MouseDown> :call BufferListMove("up")<CR>
map <silent> <buffer> <MouseUp> :call BufferListMove("down")<CR>
map <silent> <buffer> <LeftDrag> <Nop>
map <silent> <buffer> <LeftRelease> :call BufferListMove("mouse")<CR>
map <silent> <buffer> <2-LeftMouse> :call BufferListMove("mouse")<CR>
\:call LoadBuffer()<CR>
map <silent> <buffer> <Down> j
map <silent> <buffer> <Up> k

左右への動きを封じてある

map <buffer> h <Nop>
map <buffer> l <Nop>
map <buffer> <Left> <Nop>
map <buffer> <Right> <Nop>

その他編集系の機能を封じる

map <buffer> i <Nop>
map <buffer> a <Nop>
map <buffer> I <Nop>
map <buffer> A <Nop>
map <buffer> o <Nop>
map <buffer> O <Nop>

移動

map <silent> <buffer> <Home> :call BufferListMove(1)<CR>
map <silent> <buffer> <End> :call BufferListMove(line("$"))<CR>

情報収集

:set nomodifiable で調べてみた

:set buftype=nofile が出てきた

NERDTree解読

左側にどうやって split して開くのか

ファイルを選択して開くとき開き先をどうやって決めるのか

pythonに移植できんやろか

つまり、Pythonでvimから見える関数を定義できれば勝つるのでは。

vim.eval とかあるな・・・。いけるのでは?

慣れたら全部 vim script で書くようになりそうだけど、練習に移植してみよか。

nvimで、

:py3 import sys; print(sys.version)

としたら

3.6.8 (tags/v3.6.8:3c6b436a57, Dec 23 2018, 23:31:17) [MSC v.1916 32 bit (Intel)]

と返ってきた。なるほど。