vim(系)でターミナルをスプリットして左で編集、右で実行みたいなことをどうしてもしたい。そうじゃ無いともう働けない。2020年に書いてるけど、neotermが更新止まっているのといろんな環境でYouCompleteMeが動かなくなってきた。2025年の締めくくりにもう一度環境設定について見直してみた。ChatGPTに聞いたら「それ、neovim使えばできます」との返答(言い方)を得たのでやってみた。以下、設定順序
Neovimをインストール
コンパイル済みバイナリ(一番楽)
https://neovim.io/doc/install/
上記バイナリが動かなければソースからビルド
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$HOME/opt/nvim \
-DCMAKE_C_FLAGS="-D_DEFAULT_SOURCE -D_BSD_SOURCE"
cmake --build build -j
cmake --install build
Vundleをインストール
curl -fLo ~/.local/share/nvim/site/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
この動作設定ファイルを${HOME}/.config/nvim/init.vimに追記
init.vim
" ============================================================
" Neovim init.vim (UI/表示設定は除外した版)
" - 目的: コーディング/編集・補完・LSP・REPL送信を中心に整理
" - UI/表示系(行番号、colorscheme、highlight、termguicolors等)は意図的に入れていません
" ============================================================
" ------------------------------------------------------------
" 1) 基本設定(表示に依存しないものだけ)
" ------------------------------------------------------------
set nocompatible
" 文字コード(Neovimは基本UTF-8ですが、環境差があるので明示)
set encoding=utf-8
" タブ/インデント(言語ごとの上書きは ftplugin 側で可能)
set tabstop=4
set shiftwidth=4
set expandtab
" バッファを隠してもOK(未保存でも切り替え可能)
set hidden
" クリップボード共有
" - macOSローカルなら問題ないことが多い
" - リモート/HPCだと unnamedplus が効かない(外部連携がない)場合もある
set clipboard=unnamedplus
" Leader キー
let mapleader = " "
" FileType / ftplugin / indent を有効化(autocmd FileType を使うので必須)
filetype plugin indent on
" ------------------------------------------------------------
" 2) プラグイン管理(vim-plug)
" 初回: :PlugInstall
" ------------------------------------------------------------
call plug#begin('~/.local/share/nvim/plugged')
" Terminal
Plug 'akinsho/toggleterm.nvim', {'tag': '*'}
" Completion
Plug 'hrsh7th/nvim-cmp'
Plug 'hrsh7th/cmp-nvim-lsp'
Plug 'hrsh7th/cmp-buffer'
Plug 'hrsh7th/cmp-path'
Plug 'L3MON4D3/LuaSnip'
" LSP configs
Plug 'neovim/nvim-lspconfig'
" Utilities
Plug 'nvim-lua/plenary.nvim'
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
call plug#end()
" ------------------------------------------------------------
" 3) toggleterm: dev環境のshim(toggletermが vim.version モジュールを要求するケース用)
" - 一部のビルド/環境で "require('vim.version')" が無い場合に備える
" ------------------------------------------------------------
lua <<EOF
local ok = pcall(require, "vim.version")
if not ok then
package.preload["vim.version"] = function()
local v = {}
if vim.version then
local ok2, real = pcall(vim.version)
if ok2 and type(real) == "table" then
v = real
end
end
v.prerelease = v.prerelease or "dev"
return v
end
end
EOF
" ------------------------------------------------------------
" 4) toggleterm 設定
" - <C-\> でトグル
" - デフォルトは縦分割、幅は画面の半分
" ------------------------------------------------------------
lua <<EOF
local ok, toggleterm = pcall(require, "toggleterm")
if ok then
toggleterm.setup{
direction = "vertical",
open_mapping = [[<c-\>]],
size = function(term)
if term.direction == "vertical" then
return math.floor(vim.o.columns / 2)
elseif term.direction == "horizontal" then
return 15
end
return 80
end,
}
end
EOF
" ターミナルモードで ESC → ノーマルに戻る
tnoremap <silent> <ESC> <C-\><C-n>
" ------------------------------------------------------------
" 5) nvim-cmp(補完)
" - 矢印/Tabで候補移動、Enterで確定
" ------------------------------------------------------------
lua <<EOF
local ok_cmp, cmp = pcall(require, "cmp")
if ok_cmp then
local ok_luasnip, luasnip = pcall(require, "luasnip")
cmp.setup({
snippet = {
expand = function(args)
if ok_luasnip then
luasnip.lsp_expand(args.body)
end
end,
},
mapping = {
["<Down>"] = cmp.mapping.select_next_item(),
["<Up>"] = cmp.mapping.select_prev_item(),
["<Tab>"] = cmp.mapping.select_next_item(),
["<S-Tab>"] = cmp.mapping.select_prev_item(),
["<CR>"] = cmp.mapping.confirm({ select = true }),
},
sources = {
{ name = "nvim_lsp" },
{ name = "buffer" },
{ name = "path" },
},
})
end
EOF
" ------------------------------------------------------------
" 6) Treesitter(構文解析/インデント)
" - UI(ハイライト色)ではなく、構文ベースの解析機能として利用
" ------------------------------------------------------------
lua <<EOF
local ok_ts, configs = pcall(require, "nvim-treesitter.configs")
if ok_ts then
configs.setup{
highlight = { enable = true },
indent = { enable = true },
}
end
EOF
" ------------------------------------------------------------
" 7) LSP 設定
" 前提:
" Python: python3 -m pip install --user pyright
" R: R で install.packages("languageserver", lib="~/R_LIBS")
" 必要なら export R_LIBS=~/R_LIBS
"
" NOTE:
" Neovim 0.11+ では vim.lsp.enable / vim.lsp.config が使える
" それ以前は lspconfig の従来APIでフォールバック
" ------------------------------------------------------------
lua <<EOF
local has_lspconfig, lspconfig = pcall(require, "lspconfig")
if has_lspconfig then
local capabilities = require("cmp_nvim_lsp").default_capabilities()
-- Neovim 0.11+ (新API) があればそれを優先
if vim.lsp and vim.lsp.enable and vim.lsp.config then
vim.lsp.config("*", { capabilities = capabilities })
pcall(vim.lsp.enable, "pyright")
pcall(vim.lsp.enable, "r_language_server")
else
-- 旧API (nvim 0.10 以前など) フォールバック
if lspconfig.pyright then
lspconfig.pyright.setup({ capabilities = capabilities })
end
if lspconfig.r_language_server then
lspconfig.r_language_server.setup({ capabilities = capabilities })
end
end
end
EOF
" LSP 用キーマップ(よく使うものだけ)
nnoremap <silent> gd <cmd>lua vim.lsp.buf.definition()<CR>
nnoremap <silent> gD <cmd>lua vim.lsp.buf.declaration()<CR>
nnoremap <silent> gr <cmd>lua vim.lsp.buf.references()<CR>
nnoremap <silent> K <cmd>lua vim.lsp.buf.hover()<CR>
nnoremap <silent> <leader>rn <cmd>lua vim.lsp.buf.rename()<CR>
" ------------------------------------------------------------
" 8) REPL 起動 + 送信(R / Python / Shell)
"
" 仕様:
" - <C-e> を押すと:
" 1回目: トグルタームを縦分割で開き、指定REPLを起動 → その行/選択範囲を送信
" 2回目以降: 端末は維持され、送信だけ実行
"
" 実装メモ:
" - b:repl_opened は「そのバッファで既にREPLを開いたか」を覚える
" - ToggleTermSendCurrentLine / ToggleTermSendVisualSelection は toggleterm の送信コマンド
" ------------------------------------------------------------
function! ReplStart(cmd)
if !exists('b:repl_opened') || !b:repl_opened
let b:repl_opened = 1
execute 'TermExec cmd="' . a:cmd . '" direction=vertical'
endif
endfunction
function! ReplSendLine(cmd)
call ReplStart(a:cmd)
execute 'ToggleTermSendCurrentLine'
" 送信後に次の行の先頭へ(連続実行しやすくする)
normal! j^
endfunction
function! ReplSendSelection(cmd) range
call ReplStart(a:cmd)
execute 'ToggleTermSendVisualSelection'
" 送信後に選択範囲の末尾→次の行へ
normal! '>j^
endfunction
augroup ReplMappings
autocmd!
" R (.R)
autocmd FileType r nnoremap <buffer> <silent> <C-e> :call ReplSendLine('R --vanilla')<CR>
autocmd FileType r vnoremap <buffer> <silent> <C-e> :<C-u>call ReplSendSelection('R --vanilla')<CR>
" Python (.py)
autocmd FileType python nnoremap <buffer> <silent> <C-e> :call ReplSendLine('python3')<CR>
autocmd FileType python vnoremap <buffer> <silent> <C-e> :<C-u>call ReplSendSelection('python3')<CR>
" Shell (.sh, .bash, .zsh)
autocmd FileType sh,bash,zsh nnoremap <buffer> <silent> <C-e> :call ReplSendLine('bash')<CR>
autocmd FileType sh,bash,zsh vnoremap <buffer> <silent> <C-e> :<C-u>call ReplSendSelection('bash')<CR>
augroup END
" ------------------------------------------------------------
" 9) ターミナル挙動(作業効率系)
" ------------------------------------------------------------
" ターミナルバッファに入ったら常に insert/job モードで開始
augroup TermAutoInsert
autocmd!
autocmd TermOpen * startinsert
autocmd TermEnter * startinsert
augroup END
" ターミナルではマウス無効(ペースト/選択事故を減らす)
augroup NoMouseInTerm
autocmd!
autocmd TermOpen * setlocal mouse=
augroup END
" ターミナル内で <C-e><C-e> → 左側のVimウィンドウへ戻る
tnoremap <silent> <C-e><C-e> <C-\><C-n><C-w>h
必要なプラグインをインストール
:PlugInstall
Enjoy!