Open8

Neovim はじめたときの初期環境構築備忘録

64a2464a24

環境構築で行ったこと

はじめに(注意)

これは完全に個人用で作成したスクラップということを忘れないでほしい.環境依存のところもかなりあると思うので丸写しせず,必要な部分を必要なだけ切り取って使ってほしい.

環境

  • システム: Windows Subsystem for Linux 2
  • OS: Ubuntu 20.04
  • 使用ターミナル:Windows Terminal

インストール

# Update & upgrade Ubuntu 20.04 and Install neovim
sudo apt update -y
sudo apt upgrade -y
## (Omit how to install Neovim because it is written in the official website...)

# Install Python environment for Neovim
sudo pip3 install pynvim
sudo pip3 install neovim-remote

# Omit: Install jedi for deoplete-jedi and jedi-language-server for coc-jedi
#sudo pip3 install jedi
#sudo pip3 install jedi-language-server

# Install pylint for statement check (may be preinstalled)
sudo pip3 install pylint 

環境変数XDG_CONFIG_HOMEの設定

export XDG_CONFIG_HOME=~/.config/

msgpack のアップグレード(自動補完プラグイン deoplete を利用するためにはPython 用 msgpack はバージョン 1.0.0 以上が必要)

pip install --upgrade msgpack

vim-Plug のインストール

https://github.com/junegunn/vim-plug
の通りにやればよいので省略

ノーマルモード時に自動的にIMEをオフにする

下記リンクを参考:
https://wonwon-eater.com/wsl2-neovim/

軽くまとめると,githubリポジトリ https://github.com/iuchim/zenhan からzenhan.exeを任意のディレクトリに設置する.
WSL上でホームディレクトリにある.profile(すでに .bash_profileまたは.bash_loginが存在する場合はそのどちらか)に環境変数としてzenhan(適当な名前)を定義しておく.つまり,

export zenhan='/mnt/c/Users/[zenhan.exeを設置したフルパス]'

を追記する.

(注意:zenhan.exe を生成するためにはbuild.shを wsl2 から実行し、windows向けの実行ファイルを生成する必要がありため、クロスコンパイラが必要である。sudo apt install mingw-w64 g++ gcc m4を実行するで解決する)

ターミナルを再起動しコマンドプロンプトでecho $zenhanを実行したときに,先ほど定義したzenhan.exeのパスが返ってくれば,正しい.また,プロンプトでコマンドzenhan 1またはzenhan 0を実行した時に,画面右下のIMEが「あ」「A」と切り替わっていたら正しくzenhan.exeがWSL上で動いていることになる.

次にinit.vimにて実際にNeovim起動中にノーマルモードに切り替わった時にzenhan 0が実行されるように設定する.

" IME off setting
let &shell='/usr/bin/bash --login'
autocmd InsertLeave * :call system('${zenhan} 0')
autocmd CmdlineLeave * :call system('${zenhan} 0')

参考:プラグインの環境が動作条件を満たしているか確認

:checkhealth
64a2464a24

参考:init.vimの設定(完全に個人用なので使用する際は取捨選択必要)

Vimから移行したものをベースとしており,すべて確認できたわけでないので使用する際は注意

init.vim
" ================
" Basic settings
" ================
set t_Co=256
set number
set cursorline
set guifont=Ricty\ Diminished\ Discord:h13
set autoindent
set smartindent
set ambiwidth=double " Japanese input
set showmatch
set showmode
set encoding=utf-8
set fileencodings=iso-2022-jp,euc-jp,sjis,utf-8
set fileformats=unix,dos,mac
set nobackup
set laststatus=2
set mouse=a " Enable mouse wheeling
set backspace=indent,eol,start " Enable BS
set nocursorline
autocmd InsertEnter,InsertLeave * set cursorline!
" Neovim Terminal separate
if has('nvim')
  command! -nargs=* Term split | terminal <args>
  command! -nargs=* Termv vsplit | terminal <args>
endif
" IME off setting when Esc
let &shell='/usr/bin/bash --login'
autocmd InsertLeave * :call system('${zenhan} 0')
autocmd CmdlineLeave * :call system('${zenhan} 0')

" ===================
" Remap key bindings
" ===================
" NORMAL mode
noremap j gj
noremap k gk
noremap <Down> gj
noremap <Up> gk
nnoremap <S-Tab> <<

" INSERT mode
"inoremap <Up> <C-O>gk
"inoremap <Down> <C-O>gj
inoremap <Tab> <C-t>
inoremap <S-Tab> <C-d>

" edita setting
set splitbelow
set splitright
set noequalalways
set wildmenu
" Spell checking "
set spell
set spelllang=en,cjk
" cursor setting
set ruler
set cursorline
" Remember the last cursor position when leave from an editing file
autocmd BufReadPost *
	\ if line("'\"") >= 1 && line("'\"") <= line("$") && &ft !~# 'commit'
	\ |   exe "normal! g`\""
	\ | endif
" tab setting
set tabstop=2
set shiftwidth=2
" Auto-completion of parenthesis
inoremap { {}<LEFT>
inoremap [ []<LEFT>
inoremap ( ()<LEFT>
"inoremap " ""<LEFT>
"inoremap ' ''<LEFT>
inoremap {<CR> {<CR>}<ESC>O
inoremap (<CR> (<CR>)<ESC>O
" Checking Auto-completion of closing parenthesis
" Check the next character after input ) or } (closing parenthesis)
" in insert mode, then if the next character is a closing, it only
" moves cursor one character, else input a closing character.
inoremap <expr> ) strpart(getline('.'), col('.')-1, 1) == ")" ? "\<Right>" : ")"
inoremap <expr> } strpart(getline('.'), col('.')-1, 1) == "}" ? "\<Right>" : "}"
inoremap <expr> ] strpart(getline('.'), col('.')-1, 1) == "]" ? "\<Right>" : "]"
"inoremap <expr> \" strpart(getline('.'), col('.')-1, 1) == \" ? "\<Right>" : "\""
"inoremap <expr> \' strpart(getline('.'), col('.')-1, 1) == \' ? "\<Right>" : "\'"


" =====================
" Begin Vim-Plug
" =====================
"
call plug#begin('~/.vim/plugged')

  Plug 'lervag/vimtex'

  " -- Colorscheme and theme --
  Plug 'jacoborus/tender.vim'
	Plug 'itchyny/lightline.vim'
	Plug 'vim-airline/vim-airline'

  " --- Autocompletion ---
	Plug 'Shougo/deoplete.nvim', { 'do': ':UpdateRemotePlugins' }
	Plug 'deoplete-plugins/deoplete-jedi' " for Python
	"Plug 'neoclide/coc.nvim', {'branch': 'release'}
	"Plug 'pappasam/coc-jedi', { 'do': 'yarn install --frozen-lockfile && yarn build' }

  " --- ALE (Asynchronous Linting Engine) ---
  Plug 'dense-analysis/ale'

  Plug 'Vimjas/vim-python-pep8-indent'


call plug#end()
" End Vim-Plug Installation =========
"
" deoplete.nvim is enable by default
let g:deoplete#enable_at_startup = 1

" Vimtex settings
call deoplete#custom#var('omni', 'input_patterns', {
			\ 'tex': g:vimtex#re#deoplete
			\})
		
" --- ALE settings
" Setting ALE (Asyncronus Linting Engine)
let g:ale_echo_msg_error_str = 'E'
let g:ale_echo_msg_warning_str = 'W'
let g:ale_echo_msg_format = '[%linter%] %s [%severity%]'
let g:ale_lint_on_text_changed = 'always'

" Colorscheme settings
if (has("termguicolors"))
	 set termguicolors
	 let g:lightline = { 'colorscheme': 'tender' }
	" lightline
	Plug 'itchyny/lightline.vim'
	" Airline
	Plug 'vim-airline/vim-airline'
	let g:airline#extensions#tabline#enabled = 1
	let g:airline_theme = 'tender'
endif
colorscheme tender " Choose tender as colorscheme
syntax enable
filetype plugin indent on

coc-nvim を使いたいが,いまの環境(deopleteとの組み合わせ)ではエラーを吐くのでdeoplete.nvimを消して補完環境をcoc-nvimに統一すること.

64a2464a24

補足:Tmux の基本設定&キーバインド

余談:
まだWindows Terminal は分割画面(ペイン:pane)を作成(ショートカット:Alt+Shift+- または Alt+Shift+'+'でそれぞれ横分割,縦分割)したときにどのディレクトリにいたとしてもカレントディレクトリはデフォルトの%HOME%となってしまう.これに関してはまだ Microsoft は対応していない(ついでにクリップボードからペーストするときのフォーマット崩れとか,メモリ消費量が半端ない問題も修正してほしい).
そこで,Tmuxを使うことにした.Tmuxの利点はたくさんあるが,一番はシェルを閉じてもセッションが切断されないことだと思う.これにより,再度ターミナルを使うときに以前の編集状態やパスを保持した状態で作業を再開できる.

以下は https://tanakatarou.tech/25/ をもとに追記&修正

# prefixキーをC-oに変更する
set -g prefix C-t

# デフォルトでprefix がC-b になっているので、そのキーバインドを解除する
unbind C-b

# + でペインを縦に分割する
bind + split-window -h

# - でペインを横に分割する
bind - split-window -v

# ウィンドウの一覧を表示します.
bind w choose-tree -Zw

# 次のペインに移動
bind Tab select-pane -t :.+

# キーバインドの一覧を表示します.リストはC-n,C-pで移動できます.
bind ? list-keys

# prefix + rで設定ファイルをリロードする。.tmux.conf を変更したらリロード!
bind r source-file ~/.tmux.conf \; display "Reloaded!"

# Vimのキーバインドでペインの大きさを変える
bind -r C-h resize-pane -L 5
bind -r C-j resize-pane -D 5
bind -r C-k resize-pane -U 5
bind -r C-l resize-pane -R 5

# Enable mouse
set-option -g mouse on
bind -n WheelUpPane if-shell -F -t = "#{mouse_any_flag}" "send-keys -M" "if -Ft= '#{pane_in_mode}' 'send-keys -M' 'copy-mode -e'"
bind -n WheelDownPane select-pane -t= \; send-keys -M

# キーストロークのディレイを減らす
set -g escape-time 1

# ウィンドウのインデックスを1から始める
set -g base-index 1

# ペインのインデックスを1から始める
set -g pane-base-index 1

# ステータスバーを設定する
set -g status-interval 60

## ヴィジュアルノーティフィケーションを有効にする
set -g visual-activity on

## ステータスバーを上部に表示する
#set -g status-position bottom

# ステータスバーの色を設定する
set -g status-bg "colour238"

# status line の文字色を指定する。
set -g status-fg "colour255"

# Default terminal is "xterm-256color"
set -g default-terminal "xterm-256color"

# アクティブなペインのみ白っぽく変更(真っ黒は232)
set -g window-style 'bg=colour239'
set -g window-active-style 'bg=colour234'

Tmux の基本操作

上の設定をもとにまとめておく

  • tmux new -s <セッション名>:タグ<セッション名>のセッションを開始する
  • tmux a -t <セッション名>:タグ<セッション名>のセッションを再開する(アタッチ)
  • tmux kill-session -t <セッション名>:タグ<セッション名>のセッションを終了
  • <C-t>:プレフィックス
  • <C-t> d:アクティブセッションをデタッチ,抜ける(セッションは保持される)
  • <C-t>+[h/j/k/l]:アクティブペインのサイズ変更(それぞれ,左,下,上,右に伸縮)
  • <C-t> <tab>:アクティブなペインを移動する
64a2464a24

新たに覚えた基本操作

すべて https://neovim.io/doc/user/tabpage.html を参考にすればよい.一部記載する.

  • :tabnew [file]:新しいタブでファイルを開く

  • :tabc[lose][!]:現在のタブを閉じる(!を付けた場合はファイル内容に変更があっても強制的に閉じる)

  • gtまたは:tabn[ext]:次のタブに移動する

  • gT:前のタブに移動する

  • {番号}gt:指定した番号のタブへジャンプする

  • :tabs:現在開いているタブの一覧を見る

  • zg:スペルチェックの辞書への登録(英文のときカーソル上の単語が登録される)

  • zug:スペルチェック辞書から削除

  • zw:スペルチェック辞書に wrong word として登録(エディタで赤く表示される)

  • zuwzugと同じ要領

Deoplete の操作方法

  • <C-n>:次の候補
  • <C-p>:前の候補
  • <C-k>:選択,展開(確定する場合はさらにEnterを押す必要がある)
64a2464a24

Vimtex の操作

lervag/vimtexはVimでTeXファイルを編集する際に有用なプラグインである.これも開発者のリポジトリ https://github.com/lervag/vimtex#features で書かれているが,必要なものをまとめておく.

  • ノーマルモード時のカーソル移動:
    • [[,[],][,]]でそれぞれ,前のセクション前のセクションの一行前次のセクションの一行前次のセクションに移動する
    • [m,[M,]m,]Mでそれぞれ,前の環境のbegin前の環境のend次の環境のbegin次の環境のendに移動する
      以下も同じ要領で移動する.移動する環境
    • [n,[N,]n,]Nでそれぞれ,前の数式環境のbegin前の数式環境のend次の環境のbegin前の数式環境のendに移動する
    • [r,[R,]r,]Rframe環境
    • [*,]*:コメント
      Move between matching delimiters with %
    • %:デリミターの間を行き来する.例えば,
\begin{frame}{Title}
  \begin{align*}
    f(x) & = x^\top Ax \\
    g(x) & = \| x\| - 1 = 0
  \end{align*}
\end{frame}

というファイルで\begin{frame}のどこかにカーソルがある場合,一回%を押すと\end{frame}に飛び,もう一回%を押すと\begin{frame}に戻る.

  • テキストオブジェ

    • ic ac:コマンド
    • id ad:デリミター
    • ie ae:LaTeX 環境
    • i$ a$:インライン数式
    • iP aP:セクション
    • im am:箇条書き
  • その他キーマッピング

    • dsc,dse,ds$,dsd:囲まれたコマンド,環境,デリミター(機能しない)(以下同)を削除する
    • csc,cse,cs$,csd:変更
    • tsc,tse:コマンド,もしくは囲まれた環境に*を付ける
    • tsd()で実行すると\left(\right)に変える
    • tsf:インラインの分数(/で表記する.e.g. 3/4)を\frac{分子}{分母}に変える
    • (挿入モードで)]]:環境もしくはデリミターを閉じる記述を直後に自動補完
      例:\begin{frame}]]を実行すると\begin{frame}\end{frame}となる
    • <F7>:コマンドを作成する.e.g. <F7>=>sqrt<CR>=>\sqrt{}が作成される(あまり楽にならない?)
64a2464a24

締め

この二日間 Neovim の環境構築に時間を費やして思ったことは,結局手っ取り早いのは
ちゃんと DOCUMENT を読むことである.DOCUMENTの情報量は半端でないが,適宜検索などで絞り込んで効率よく欲しい情報を一次ソースから得る習慣をつけたい.
楽そうだからという理由で,こうしたまとめ記事で目に留まったものに頼ってもいいけども,割と暗に環境依存して書かれていることがあって結局調べなおすということが半分以上の時間費やしていた気がする.

64a2464a24

Pylint のモジュールインポートエラーを解決する

Pylint を使ったリアルタイム構文チェックをNeovimで利用する場合,ユーザーが作成したモジュールが読み込まれなくてnot definedが出て邪魔に感じるだろう(プログラムを動かすときは問題ないにもかかわらず).その対策として,.pylintrcを作業フォルダに作成する.

参考(修正):https://blog.515hikaru.net/entry/2017/01/26/031311

pylint --generate-rcfile >> .pylintrc

作業フォルダー上で.pylintrcを作成して開くといろいろ書き込まれているが,[MASTER]部分にコメントアウトで#init-hook=という行があると思う.ここをコメントを外してカレントディレクトリをpylintのパスに追加すれば問題なく作業ディレクトリ上の作成したモジュール(python プログラム)が読み込まれる.

.pylintrc
init-hook='import sys; sys.path.append(".")'
64a2464a24

自動補完に coc.nvim を使用する場合

はじめに

Coc.nvim で自動補完プラグインを管理する場合,先に紹介したdeopleteと競合するため,根本的に見直さなければならないので,本スクラップでフォーカスする Python 以外にも vimtex といった類のものもcoc-vimtexhttps://github.com/neoclide/coc-vimtex )をインストールする必要がある.また,Deoplete との大きな違いとしてはほとんどメジャーな言語の自動補完はcoc-[言語名]でパッケージが用意されているため管理しやすい.しかし,体感として補完タブの動作言語は deoplete の Python と違って,JavaScriptということもあるのか若干遅い(正直本格的に調査していないので何とも言えない).

Node.js のインストール

WSL に Node.js をインストールする(Cocの起動に必要).
Node.js最新版のWSLへのインストール方法はすでに紹介されている諸記事を参考.

coc.nvim と Python 用の補完環境coc-jediの構築

注意
先述したように,既に紹介した自動補完プラグインdeopleteと競合するので,init.vimPlug 'Shougo/deoplete.nvim', {'...Plug 'deoplete-plugins/deoplete-jedi'の行をコメントアウトし,:PlugCleanで拡張機能を削除する

  • Plug 'neoclide/coc.nvim', {'branch': 'release'}を追加し,:PlugInstallcoc.nvimをインストールする.
  • :CocInstall coc-jediでPython自動補完プラグイン(coc-jedi)をインストールする.
  • init.vimで以下の行を追加
autocmd FileType python let b:coc_root_patterns = ['.git', '.env']

同時にdeoplete に関する記述

let g:deoplete#enable_at_startup = 1

call deoplete#custom#var('omni',...

をコメントアウトする.

  • coc-settings.json~/.config/nvim/に用意する.以下の設定を記述すると,MSLS (Microsoft Language Server) でリアルタイムに構文データを参照する(jsonにはコメント構文がないので#以降は消すこと!).
coc-settings.json
{
  "python.jediEnabled": true, # いらないかも
  "jedi.enable": true,
  "jedi.startupMessage": false,
  "jedi.markupKindPreferred": "plaintext",
  "jedi.trace.server": "off",
  "jedi.jediSettings.autoImportModules": [],
  "jedi.executable.command": "jedi-language-server",
  "jedi.executable.args": [],
  "jedi.completion.disableSnippets": false,
  "jedi.completion.resolveEagerly": false,
  "jedi.diagnostics.enable": true,
  "jedi.diagnostics.didOpen": true,
  "jedi.diagnostics.didChange": true,
  "jedi.diagnostics.didSave": true,
  "jedi.workspace.extraPaths": ["."], # 公式は`[]`だがこれだと作業フォルダ内のモジュールが読み込まれないのでカレントを追加しておく
}

開発時の注意:PYTHONPATHの指定

.pylint の設定でも書いた理由と同じようにcoc-pythonで自動補完を行う場合,以下のファイルを作業フォルダに用意することで,パーサーが作業ディレクトリのモジュールデータベースを構築するため,インポートエラーが出力されなくなる.

.env
PYTHONPATH="[pythonx.xがあるパス]/pythonx.x/site-packages"

要するに Neovim で Python 開発環境で自動補完を実現するために別途必要なファイルは

  • .envPYTHONPATHの定義
  • .pylintrc:Python 用 linting 設定ファイル(pylint --generate-rcfile >> .pylintrcで作成し,`init-hookを追加)