neovim × neoterm = 最強

vimmerの皆さんこんにちは。

今回はneovimにて実装されたターミナルモードの便利な使い方を紹介していきます。
通常のvimでも、ターミナルコマンドを使うことができましたが、neovimではもうターミナルそのものを使用できるのでとても便利です。
(厳密には違う?かもしれませんが、今の所通常のターミナルとの相違点は無いように感じます)

参考:私が使用している便利なプラグイン一覧
vim とても強力なプラグインたち

neovim × neotermでできること   (私がやっていること…)

vimからコマンド1つで

  • Python を走らせる
  • c++ をコンパイル (cmake)
  • texをコンパイル
  • catkin_make (ROS) を実行

といった便利なことができます.みなさんもぜひneovimでターミナルモードを使いこなしましょう.

ちなみに,私はvimのnormalモード中で
<Space>p 画面を上下に分割し、下半分にターミナルを出現させ現在編集していたPythonスクリプトを実行。
<Space>c 画面を上下に分割し、下半分にターミナルを出現させROSのcatkin_makeを実行。
という風にキーマッピングをしています。

neotermとは

kassio氏が公開しているneovimのターミナルに関するプラグインです。

kassio/neotermのgithubページはこちら。
https://github.com/kassio/neoterm

例えば、、、こんなことができます。

ターミナルウィンドウの表示に関するマッピング

neotermを入れたら、まずはターミナルウィンドウを表示させたいですよね。
そこで以下のようにマッピングします。

nnoremap <c-t><c-t> :Ttoggle<CR>
tnoremap <c-t><c-t> <C-¥><C-n>:Ttoggle<CR>

割り当てるキーは皆さんのお好みのマッピングにしてもらえば良いのですが、参考までに私は Ctrl + t のダブルタップに割り当てています。

:Ttoggleはneotermのコマンド。ターミナルウィンドウのトグル(on-offの切替)です。

ターミナルモード中はコロンで始まるコマンドは入力できないので、一度 <C-\><C-n> でターミナルモードを抜けてノーマルモードに戻ってから :Ttoggle コマンドを実行します。

ターミナルウィンドウのサイズを変更する

neotermではデフォルトで画面半分のサイズのターミナルウィンドウが出現すると思いますが、変数をイジればお好みのサイズに変更することができます。

let g:neoterm_size = winheight(0)/3
augroup AutoTermHeight
  autocmd!
  autocmd VimResized * let g:neoterm_size = winheight(0)/3
augroup END

グローバル変数 g:neoterm_size に値を入れることで、ターミナルウィンドウの行数を調節します。

上記例のように、私はターミナルウィンドウのサイズを画面三分の一の高さになるように設定しています。また、オートコマンドで画面がリサイズされる度に g:neoterm_sizeをアップデートしています。

neotermの基本的なコマンド

:Tnew
ターミナルを開くコマンドです。
初期設定では水平方向に画面が分割されるが、設定によっては垂直方向に分割したり、新しいウィンドウで開くこともできるようになります。
Ctrl + dで端末を終了させると自動的に分割されたウィンドウが閉じられます。

:T <command>
ターミナルを開き,コマンドを実行します。
例えば、:T cd ~/Documents など。

nnoremap (keymapping) :T (command)<CR>
nnoremap (keymapping) :T (command)<CR><C-w>j

このようにマッピングすると良いと思います。
2段目は、分割した後にターミナルのウィンドウに移動するバージョンです。ターミナルを水平分割で開いた後もフォーカスは元のウィンドウのままとなるので、<C-w>j でターミナルのウィンドウにフォーカスを移動しています。
どちらが使いやすいかはお好みで。

現在編集しているpythonプロジェクトを走らせる

画面下半分にターミナルウィンドウが出現して、現在編集しているpythonを走らせることができます。

nnoremap @p :T python %<CR><c-w>j

:T
ターミナルを開く。

python %<CR>
pythonを走らせる。(%はカレントファイル名を表します。)

<c-w>j
水平分割で開いた後に、ターミナルにフォーカスを移動。この記述はお好みでどうぞ。

cmakeを走らせる

同様にcmakeを走らせる。

nnoremap @C :T cd %:h && cd ../build && cmake .. && make<CR><c-w>j

:T
ターミナルを開く。

cd %:h
今編集しているファイルがあるフォルダに移動。(%:hで現在開いているファイルのディレクトリを取得できます。)

cd ../build
今いるフォルダからbuildフォルダに移動します。

cmake .. && make
cmakeを実行。

お気づきかもしれませんが,これだと1つ上の階層がプロジェクトのルート(CMakeLists.txtのある場所)だと決め打ちしています.
ちゃんと使えるようにするならCMakeLists.txtのあるディレクトリに移動するシェルを書く必要があるとおもいますが…

catkin_makeを走らせる (ROS)

同様にcatkin_makeを走らせる.

nnoremap <silent> @c :T roscd && catkin_make<CR><c-w>j

:T
ターミナルを開く。

roscd
catkin_wsに移動する。

catkin_make
catkin_makeを実行。

その他

最近は、コマンド1つでgitにpushする機能を割り当てたり、
コマンド1つでTexのコンパイルが実行できるようにしてみたりと、
(日本語の文書作成にvimを使うとは何事か!と突っ込まれそうですが、それでも私はvimを使います。Vim愛。)
ターミナルを用いるショートカットを色々と考えてはvimrcの行数を増やしています。

アイデア次第でNeotermを用いて様々なショートカットが考えられると思います。

dein.tomlでのNeotermの設定

私がdein(プラグイン管理のためのプラグイン)で設定しているtomlファイルを載せておきます。

私が記述している主な設定

  • 水平分割でターミナルを開く
  • 垂直分割でターミナルを開く
  • 新しいタブでターミナルを開く
  • 新しいタブでターミナルを複数開く(2×2, 2×3, 2×4)
  • CMakeを走らせる
  • CatkinMakeを走らせる
  • 現在開いているPythonスクリプトを走らせる
  • 現在開いているTexをコンパイルする
  • Neovimのconfigファイルをアップデート(~/.config/nvim をgit pull)
  • 現在開いているファイルを含んだgitディレクトリをコメント付でgit push

一部では、外部シェルスクリプトに依存しているものもありますが。

# neovim terminal plugin
[[plugins]]
repo = 'kassio/neoterm'
hook_add = '''
	let g:neoterm_autoinsert = 1
	let g:neoterm_autoscroll = 1
	" # let g:neoterm_split_on_tnew = 1
	let g:neoterm_default_mod = "belowright"

  let g:neoterm_size = winheight(0)/3
  augroup AutoTermHeight
    autocmd!
    autocmd VimResized * let g:neoterm_size = winheight(0)/3
  augroup END

	function! NTermInNewTab()
		let l:tmp = g:neoterm_default_mod
		let g:neoterm_default_mod = "tab"
		Tnew
		let g:neoterm_default_mod = l:tmp
	endfunction

	function! NTermCurrentDir()
		let l:cmd = "cd " .expand("%:p:h")
		call neoterm#exec({ 'cmd': [ cmd , '' ] })
		Topen
	endfunction

	function! NTermCMake()
		let l:cmd = "cd " .expand("%:p:h")
		let l:cmd = l:cmd . " && source ~/.config/nvim/scripts/AutoCMake.sh"
		call neoterm#exec({ 'cmd': [ cmd , '' ] })
		Topen
	endfunction

	function! NTermCatkinMake()
		let l:cmd = "roscd"
		let l:cmd = l:cmd . " && catkin_make"
		call neoterm#exec({ 'cmd': [ cmd , '' ] })
		Topen
	endfunction

	function! NTermPython( ... )
		if expand("%:e") != 'py'
			echo '[error] Invalid file extension.'
			return
		endif
		let l:cmd = "python " .expand("%:p")
		for arg in a:000
			let l:cmd = l:cmd . " " . arg
			"let l:cmd.cmd = [ l:cmd.cmd, arg ]
		endfor
		call neoterm#exec({ 'cmd': [ cmd ] })
		"T python l:cmd
		Topen
	endfunction

	function! NTermTexCompile()
		if expand("%:e") != 'tex'
			echo '[error] Invalid file extension.'
			return
		endif
		let l:cmd = "cd " .expand("%:p:h")
		let l:cmd = l:cmd . " && platex " . expand("%:p")
		let l:cmd = l:cmd . " && dvipdfmx " . expand("%:p:r") . ".dvi"
		call neoterm#exec({ 'cmd': [ cmd , '' ] })
		Topen
	endfunction

	function! GitPush( comment )
		let l:cmd = "cd " .expand("%:p:h")
		let l:cmd = l:cmd . " && source ~/.config/nvim/scripts/GitPush.sh " . a:comment
		call neoterm#exec({ 'cmd': [ cmd , '' ] })
		Topen
	endfunction

	function! UpdateConfig()
		let l:cmd = "cd ~/.config/nvim"
		let l:cmd = l:cmd . " && git pull"
		call neoterm#exec({ 'cmd': [ cmd , '' ] })
		Topen
		" execute "source ~/.config/nvim/init.vim"
	endfunction

	function! NTermMulti( v_num, h_num )
		let l:tmp = g:neoterm_default_mod
		let g:neoterm_default_mod = "tab"
		Tnew
		" # vertical split
		let g:neoterm_default_mod = "vertical"
		for i in range( a:h_num - 1 )
			Tnew
		endfor
		" # holizontal split
		let g:neoterm_default_mod = "aboveleft"
		for i in range( a:h_num )
			for i in range( a:v_num - 1 )
				Tnew
			endfor
			" # move to left window
			execute "winc l"
		endfor
		" # move to top-left window
		execute "winc t"
		let g:neoterm_default_mod = l:tmp
	endfunction

	function! NTermHolizontalSplit()
		let l:tmp = g:neoterm_default_mod
		let g:neoterm_default_mod = "aboveleft"
		Tnew
		let g:neoterm_default_mod = l:tmp
	endfunction

	function! NTermVerticalSplit()
		let l:tmp = g:neoterm_default_mod
		let g:neoterm_default_mod = "vertical"
		Tnew
		let g:neoterm_default_mod = l:tmp
	endfunction

	nnoremap <silent> <c-t><c-t> :Ttoggle<CR>
	tnoremap <silent> <c-t><c-t> <C-\><C-n>:Ttoggle<CR>
	nnoremap <c-t><c-h> :call NTermHolizontalSplit()<CR>
	nnoremap <c-t><c-v> :call NTermVerticalSplit()<CR>

	command! CMake                call NTermCMake()
	command! CatkinMake           call NTermCatkinMake()
	command! -nargs=* Python      call NTermPython(<f-args>)
	"command! -nargs=* Python      :T python %:p <f-args>
	command! TexCompile           call NTermTexCompile()
	command! UpdateConfig         call UpdateConfig()
	command! -nargs=1 GitPush     call GitPush(<f-args>)
	command! -nargs=+ NTermMulti  call NTermMulti(<f-args>)
	command! NTermMulti4          call NTermMulti(2,2)
	command! NTermMulti6          call NTermMulti(3,2)
	command! NTermMulti8          call NTermMulti(4,2)
'''

みなさんもNeotermを用いて便利なショートカットを色々割り当ててみてはいかがでしょう。
それでは。

参考:私が使用している便利なプラグイン一覧
vim とても強力なプラグインたち