Skip to content
Update vim authored by umaumax's avatar umaumax
[[_TOC_]]
## 💡how to update plugins
``` bash
brew upgrade nvim
```
``` vim
:PlugUpdate
:TSInstall all
:TSUpdate
:checkhealth
:checkhealth nvim-treesitter
```
* エラーが発生した場合は、GitHubで該当するpluginのissueを探す
* pluginのon/offを試してみる
e.g.
* [nvim-treesitterで「query: invalid node type at...」エラーが出た #neovim - Qiita]( https://qiita.com/ZOI_dayo/items/3c39252c729dd27393f3 )
* [Highlights broken after update with `query: invalid structure` · Issue #3092 · nvim-treesitter/nvim-treesitter]( https://github.com/nvim-treesitter/nvim-treesitter/issues/3092 )
## オレオレコードリーディングチートシート
マッピング
* S: 関数やシンボルなどの一覧を表示して飛ぶ
* _: 型の定義へ飛ぶ
* H: 型やメソッドの情報を表示
* K: 定義へ飛ぶ
* R: 利用されている箇所の一覧して飛ぶ
コマンド
* FZFbuffers: バッファ一覧を表示して切り替え
* RenameRefactor: 変数名などを一括変更する
fzf
* L: 行を検索する
### マークダウン
* `:Unite outline`: 見出しジャンプ
### 移動
* `g<space>` + 2文字入力: 画面内移動
* `[`,`]`: 関数ごとにジャンプ
* `{`,`}`: ブロック?ごとにジャンプ
* [stevearc/aerial.nvim: Neovim plugin for a code outline window]( https://github.com/stevearc/aerial.nvim#keymaps )
* `AerialToggle`: 関数などのシンボルを一覧表示してジャンプ可能
* 自作ショートカットでは`<Leader>A``AerialOpen`
### ショートカットメモ
* [tpope/vim-abolish: abolish.vim: easily search for, substitute, and abbreviate multiple variants of a word]( https://github.com/tpope/vim-abolish )
``` vim
" crs "SnakeCase" -> "snake_case"
" crm "mixed_case" -> "MixedCase"
" crc "camel_case" -> "camelCase"
" cru "upper_case" -> "UPPER_CASE"
call extend(Abolish.Coercions, { 'c': Abolish.camelcase,
\ 'm': Abolish.mixedcase,
\ 's': Abolish.snakecase,
\ '_': Abolish.snakecase,
\ 'u': Abolish.uppercase,
\ 'U': Abolish.uppercase,
\ '-': Abolish.dashcase,
\ 'k': Abolish.dashcase,
\ '.': Abolish.dotcase,
\ ' ': Abolish.spacecase,
\ 't': Abolish.titlecase,
\ "function missing": s:function("s:unknown_coercion")
\}, "keep")
```
## how to build vim
[vim\-jp » Linuxでのビルド方法]( https://vim-jp.org/docs/build_linux.html )
<details>
<summary>how to build</summary>
<!-- you must insert blank line -->
``` bash
$ git clone https://github.com/vim/vim.git
$ cd vim
$ ./configure --with-features=huge \
--enable-multibyte \
--enable-fontset \
--enable-fail-if-missing \
--prefix=$HOME/local \
--enable-pythoninterp=yes \
--enable-python3interp=yes
$ make -j8
$ ./src/vim --version
VIM - Vi IMproved 8.2 (2019 xxx, compiled xxx)
Included patches: 1-19
Compiled by xxx
Huge version with GTK2 GUI. Features included (+) or not (-):
+acl -farsi -mouse_sysmouse -tag_old_static
+arabic +file_in_path +mouse_urxvt -tag_any_white
+autocmd +find_in_path +mouse_xterm -tcl
+autochdir +float +multi_byte +termguicolors
-autoservername +folding +multi_lang +terminal
+balloon_eval -footer -mzscheme +terminfo
+balloon_eval_term +fork() +netbeans_intg +termresponse
+browse +gettext +num64 +textobjects
++builtin_terms -hangul_input +packages +textprop
+byte_offset +iconv +path_extra +timers
+channel +insert_expand -perl +title
+cindent +job +persistent_undo +toolbar
+clientserver +jumplist +popupwin +user_commands
+clipboard +keymap +postscript +vartabs
+cmdline_compl +lambda +printer +vertsplit
+cmdline_hist +langmap +profile +virtualedit
+cmdline_info +libcall +python/dyn +visual
+comments +linebreak +python3/dyn +visualextra
+conceal +lispindent +quickfix +viminfo
+cryptv +listcmds +reltime +vreplace
+cscope +localmap +rightleft +wildignore
+cursorbind -lua -ruby +wildmenu
+cursorshape +menu +scrollbind +windows
+dialog_con_gui +mksession +signs +writebackup
+diff +modify_fname +smartindent +X11
+digraphs +mouse -sound -xfontset
+dnd +mouseshape +spell +xim
-ebcdic +mouse_dec +startuptime -xpm
+emacs_tags -mouse_gpm +statusline +xsmp_interact
+eval -mouse_jsbterm -sun_workshop +xterm_clipboard
+ex_extra +mouse_netterm +syntax -xterm_save
+extra_search +mouse_sgr +tag_binary
system vimrc file: "$VIM/vimrc"
user vimrc file: "$HOME/.vimrc"
2nd user vimrc file: "~/.vim/vimrc"
user exrc file: "$HOME/.exrc"
system gvimrc file: "$VIM/gvimrc"
user gvimrc file: "$HOME/.gvimrc"
2nd user gvimrc file: "~/.vim/gvimrc"
defaults file: "$VIMRUNTIME/defaults.vim"
system menu file: "$VIMRUNTIME/menu.vim"
fall-back for $VIM: "~/local/share/vim"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H -DFEAT_GUI_GTK -pthread -I~/.linuxbrew/Cellar/pcre/8.42/include -I~/.linuxbrew/Cellar/expat/2.2.6/include -I/usr/include/gtk-2.0 -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include -I/usr/include/gio-unix-2.0/ -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/libpng12 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/freetype2 -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
Linking: gcc -L/usr/local/lib -Wl,--as-needed -o vim -lgtk-x11-2.0 -lgdk-x11-2.0 -lpangocairo-1.0 -latk-1.0 -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lpangoft2-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lfontconfig -lfreetype -lSM -lICE -lXt -lX11 -lXdmcp -lSM -lICE -lm -ltinfo -lnsl -lacl -lattr -ldl
```
</details>
## how to name plugins
* `*.vim`
* `vim-*`
## Vim script
### snippet
#### visualモードで選択しているテキスト操作
[vim \- How to get visually selected text in VimScript \- Stack Overflow]( https://stackoverflow.com/questions/1533565/how-to-get-visually-selected-text-in-vimscript )
``` vim
function! s:get_visual_selection()
" Why is this not a built-in Vim script function?!
let [line_start, column_start] = getpos("'<")[1:2]
let [line_end, column_end] = getpos("'>")[1:2]
let lines = getline(line_start, line_end)
if len(lines) == 0
return ''
endif
let lines[-1] = lines[-1][: column_end - (&selection == 'inclusive' ? 1 : 2)]
let lines[0] = lines[0][column_start - 1:]
return join(lines, "\n")
endfunction
function! s:delete_visual_selection()
let selected = s:get_visual_selection()
call setpos('.', getpos("'<"))
let Mlen = { s -> strlen(substitute(s, ".", "x", "g"))}
let l = Mlen(selected)
if l > 0
execute "normal! v".(l-1)."\<Right>\"_x"
endif
return selected
endfunction
```
#### 特定行に内容をセットする
``` vim
function! s:setlines(pos, lines)
if len(a:lines)==0
execute ':'.a:pos.'d'
return
endif
call setline(a:pos, a:lines[0])
call append(a:pos, a:lines[1:])
endfunction
```
#### 範囲選択コマンド
``` vim
function! XXX() range
for n in range(a:firstline, a:lastline)
let line = getline(n)
endfor
endfunction
command! -range XXX <line1>,<line2>call XXX()
```
#### 外部コマンド
[vim-clang-format/clang_format.vim at master · rhysd/vim-clang-format]( https://github.com/rhysd/vim-clang-format/blob/master/autoload/clang_format.vim#L14 )
``` vim
function! s:has_vimproc() abort
if !exists('s:exists_vimproc')
try
silent call vimproc#version()
let s:exists_vimproc = 1
catch
let s:exists_vimproc = 0
endtry
endif
return s:exists_vimproc
endfunction
function! s:success() abort
let l:exit_success = (s:has_vimproc() ? vimproc#get_last_status() : v:shell_error) == 0
return l:exit_success
endfunction
function! s:error_message(result) abort
echohl ErrorMsg
echomsg 'xxx has failed to yyy.'
for l:line in split(a:result, "\n")[0:1]
echomsg l:line
endfor
echohl None
endfunction
```
### 行継続時のコメント
``` vim
let hoge = {
\ "a": 1,
"\ comment \の後に必ずスペースを入れること
\ "b": 2
\ }
```
[Twitter]( https://twitter.com/Bakudankun/status/1334618416951463937 )
### [実は必要のないset nocompatible]( https://github.com/vim-jp/reading-vimrc/wiki/vimrc%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3#%E5%AE%9F%E3%81%AF%E5%BF%85%E8%A6%81%E3%81%AE%E3%81%AA%E3%81%84set-nocompatible )
### 他のバッファの行数のみを知りたいが,vim単体では行全体を取得してから長さ取得となる
[Is there a way to get the number of lines of a buffer in Vim Script? \- Stack Overflow]( https://stackoverflow.com/questions/14544618/is-there-a-way-to-get-the-number-of-lines-of-a-buffer-in-vim-script )
### sortしたい
``` vim
# builtin command
:{range}sort
# unix command
:{range}!sort
```
### expand - スクリプトのディレクトリ自体を取得する
[Vimスクリプトでスクリプトのディレクトリを取得する -- ぺけみさお]( https://www.xmisao.com/2014/05/28/vim-get-script-path.html )
### match, 2match, 3match
[pattern \- Vim日本語ドキュメント]( https://vim-jp.org/vimdoc-ja/pattern.html#:2match )
prefixがつくと別々の独立したマッチを行う
[nvim\-treesitter/nvim\-treesitter: Nvim Treesitter configurations and abstraction layer]( https://github.com/nvim-treesitter/nvim-treesitter )有効時には`2match``3match`で設定しないとハイライトされないことに注意
`matchadd`関数を利用すると各ウィンドウごとに確実にシンタックスハイライトが可能となる
### visual mode
#### 矩形選択(ctrl-v)
[visual \- Vim日本語ドキュメント]( https://vim-jp.org/vimdoc-ja/visual.html#CTRL-V )
> WindowsではCTRL-Vはテキストの貼り付けにマップされることがあり、その際にはビジュアルモードを開始できない。[CTRL-V-alternative]( https://vim-jp.org/vimdoc-ja/gui_w32.html#CTRL-V-alternative )
を参照。
> CTRL-Vがペーストに使われてしまうので、矩形ビジュアル選択を開始することができな
い。これにはCTRL-Qを代用できる。
#### `'<,'>` range機能
行単位(~~文字単~~)
#### [visualモードで選択した範囲に含まれる「行」ではなく、選択した「テキスト」にだけ置換処理を適用する。 — 名無しのvim使い]( http://nanasi.jp/articles/howto/editing/replace-selecttext.html )
置換対象の先頭に`\%V`を付加する
### visual modeの種類を判定したい
`visualmode()`
`v`,`V`,`^V`?
#### [ビジュアルモードの選択情報の取得 — 名無しのvim使い]( http://nanasi.jp/articles/code/screen/visual.html )
``` vim
:let tmp = @@
:silent normal gvy
:let selected = @@
:let @@ = tmp
:echo selected
```
#### visual mode時に関数を呼びたい
``` vim
vnoremap :<C-u>call xxx<CR>
```
`<C-u>`でrangeを無効化
[vimrcでのキーマッピングの際の意味 \- e\_v\_e’s blog]( http://e-v-e.hatenablog.com/entry/20150101/1420067539 )
### cmdline mode判定
`getcmdtype()`
```
> debug mode command |debug-mode|
/ forward search command
? backward search command
@ |input()| command
- |:insert| or |:append| command
= |i_CTRL-R_=|
```
### 無名バッファを開いてpasteしたい
e.g. paste z regster
``` vim
tabnew | exe "normal! \"zp"
```
### 編集しても:qで警告なしに終了可能なバッファにしたい
``` vim
:setlocal buftype=nofile
```
### get window width
[Get "usable" window width in vim script \- Stack Overflow]( https://stackoverflow.com/questions/26315925/get-usable-window-width-in-vim-script )
``` vim
:set virtualedit=all
:norm! g$
:echo virtcol('.')
```
### original commandに`-bar`オプションがない場合
wrapperを定義すれば良い
``` vim
autocmd BufWritePre *.go if IsAutoFormat() | :GoFmtWrapper | endif
" NOTE: original GoFmt has no '-bar' option
command! -bar GoFmtWrapper :GoFmt
```
### `range`なfunctionを他のcommandとしてではなくfunctionとして呼びたい
[vimscript \- Run global with range from within function \- Vi and Vim Stack Exchange]( https://vi.stackexchange.com/questions/9037/run-global-with-range-from-within-function )
``` vim
4,8call Function()
```
### メッセージに出力する形式での変数の値確認
`echom string(xxx)`とすると`echo`のように任意の型に対して利用できる
### コマンドのログ付き実行
`:99verbose COMMAND`
### 行操作
``` vim
setline()
append()
" NOTE: 対象がfoldされているとすべて消える
execute 'normal! "_dd'
# 現在の見ている範囲
let topline = line("w0")
let bottomline = line("w$")
let lastline = line("$")
```
#### 現在位置に挿入
``` vim
call setline('.', line[:col('.')-1] . repeat(' ', &tabstop) . line[col('.'):])
call cursor('.', col('.')+&tabstop)
```
[vimscript - How can I append text to the current line? - Vi and Vim Stack Exchange]( https://vi.stackexchange.com/questions/12445/how-can-i-append-text-to-the-current-line )
### source
#### 実はURLを指定してファイルを読み込むことができる
とある環境の内部では`wget`が実行されていた
e.g. `source https://raw.githubusercontent.com/mhinz/vim-galore/master/static/minimal-vimrc.vim`
#### sourceしたvimファイル中での早期return
`finish`
### 関数内で関数定義可能
e.g. [vim\-codefmt/yapf\.vim at 5ede026bb3582cb3ca18fd4875bec76b98ce9a12 · google/vim\-codefmt]( https://github.com/google/vim-codefmt/blob/5ede026bb3582cb3ca18fd4875bec76b98ce9a12/autoload/codefmt/yapf.vim#L28 )
### コマンド
#### `<Plug>`なキーマップをコマンドから呼びたい
[Vim の \<Plug> ってなんだ? - Qiita]( https://qiita.com/domodomodomo/items/043e1f8d0f2a08ad0c53 )
`command! PreviewGitDiff call feedkeys("\<Plug>(GitGutterPreviewHunk)")`
### キーマップ
[Mapping keys in Vim \- Tutorial \(Part 1\) \| Vim Tips Wiki \| FANDOM powered by Wikia]( http://vim.wikia.com/wiki/Mapping_keys_in_Vim_-_Tutorial_(Part_1) )
`<sciprt>`を付加すると意図しない上書きを禁止しやすい
> The following characters may be displayed before the {rhs} of the map:
```
* The {rhs} of the map is not re-mappable. Defined using the
':noremap' or ':nnoremap' or ':inoremap', etc. commands.
& Only script local mappings are re-mappable in the {rhs} of the
map. The map command has the <script> attribute.
@ A buffer local map command with the <buffer> attribute.
```
#### 割当不可
* `ctrl-;`,`ctrl-:`
* `ctrl-,`,`ctrl-.`
* `<S-Space>`
* `<C-S-xxx>`
`inoremap``<ESC>`をマッピングすると、矢印移動でABCDが入力される問題が発生する
#### `<C-u>`
`nnoremap <Space>w :<C-u>w<CR>``<C-u>`は範囲指定の数字を削除するため
#### 特定のキーがマッピングされているかどうか
``` vim
maparg('hoge')
maparg('<S-Tab>', 'i')
!empty(maparg('hoge'))
```
### 判定
#### 関数の存在判定
[vim \- VimL: Checking if function exists \- Stack Overflow]( https://stackoverflow.com/questions/13710364/viml-checking-if-function-exists )
* `"`で囲むこと
* `*`を付加すること
``` vim
if exists("*GitBranchInfoString")
" do stuff here
endif
```
#### 関数が定義されているファイルを調べる
`:verbose function /FunctionNameRegex/`
#### vimコマンドの判定
`exists(":HogeCommand")`
注意点: help existsより、完全一致の場合は2が返されるが、完全一致せずに、`:HogeCommandPlus`にマッチした場合は1となる
```
1 for match with start of a command
2 full match with a command
3 matches several user commands
To check for a supported command always check the return value to be 2.
```
#### プラグインの読み込み判定
``` vim
if &rtp =~ 'plugin-name'
...
endif
```
``` vim
if &rtp !~ 'non-exist-plugin-name'
...
endif
```
[Vim script の exists で autoload の関数は判定してはいけない \- C\+\+でゲームプログラミング]( http://d.hatena.ne.jp/osyo-manga/20120412/1334158849 )
#### 変数の存在判定
`exists('v:t_number')`
#### type detection
`:h type()`
### autocmd
* [autocmd-once]( https://vim-jp.org/vimdoc-en/autocmd.html#autocmd-once )
* one-shotなイベント向け
* [autocmd-nested]( https://vim-jp.org/vimdoc-en/autocmd.html#autocmd-nested )
* autocmdトリガー中に他のautocmdのトリガー向けに意図的にイベントの発生を許容してネストさせる
### runtime
``` vim
runtime! xxx/yyy/zzz/*.vim
```
ではパスが適切でなくともエラーが表示されないので注意
### execute
* `call execute("echo 42")`: 出力されない
* `echo execute("echo 42")`: 出力される
* `call execute("echo 42", "")`: 出力される
### 変数のプリフィックス
* `l:`: ローカル変数(関数内部のデフォルト接頭辞であるので、省略可)
* `g:`: グローバル変数(関数外の場合のデフォルト)
* `v:`: 特殊な変数のみ
* `b:`: バッファローカル
* 新規バッファになったときに,autocmd系から呼ばれるときにも初期化された状態となる
* `w:`: ウィンドウローカル
* `t:`: タブローカル
* `s:`: スクリプトローカル
#### バッファローカルな変数を利用して状態を保持したい
単純に`.vimrc`に定義を書いた場合には、単に最初のバッファのみに実体が生成されるだけで、他のバッファを開いたときにその変数の値を読み込もうとするとエラーとなるので、その変数を利用する関数内の先頭などで下記のようにデフォルト値を設定する必要がある
``` vim
let b:hoge = get(b:, 'hoge', 'default value')
```
### 正規表現
* `\+`
* `\(`,`\)`
* `^`,`$`,`.`
* `*`:最長マッチ
* `\{-}`:最短マッチ
* `\zs`:どこにでもマッチしてマッチの開始地点を設定する
### for
``` vim
for l:n in range(0, 10)
endfor
```
``` vim
for l:val in l:list
endfor
```
``` vim
for l:key in keys(l:map)
let l:val = l:map[l:key]
endfor
```
### filename
* 現在のファイルを対象:`expand`
* 変数を対象:`fnamemodify`
### save & restore settings
#### cursor
```
let l:view = winsaveview()
...
silent call winrestview(l:view)
```
#### window
```
let save_winnr = winnr()
...
exe save_winnr. 'wincmd w'
```
#### user setting
```
" push user setting
let s:save_cpo = &cpo
set cpo&vim
" write plugin script here
" pop user setting
let &cpo = s:save_cpo
unlet s:save_cpo
```
### insert modeからcommand line modeへ移動する例
* `<ESC>:xxx<CR>i`:カーソルがずれる
* `<C-o>:xxx<CR>`:カーソルがずれない
### vimscriptの実行結果を変数に格納して、その変数を外部コマンドへパイプする例
```
silent! redir => commands
silent! scriptnames
silent! redir END
echo(system('grep ".vim"', commands))
```
### multiple filetype
通常,使えない
[Multiple file types in vim \- Stack Overflow]( https://stackoverflow.com/questions/2601403/multiple-file-types-in-vim )
> ou can specify to use multiple filetypes at the same time. For example:
> :setfiletype html.php
> But most of filetype plugings and syntax files are not designed for such cases. See also :help 'filetype'
[複数の'filetype'を扱いたい · Issue \#1034 · vim\-jp/issues]( https://github.com/vim-jp/issues/issues/1034 )
### exit code
`v:shell_error`
### 文字列処理
#### 文字列の文字を配列の要素とする
e.g. `"abc" -> ['a', 'b', 'c']`
```
let l:key_mapping = "asdfghjklzxcvbnmqwertyuiop"
let g:key_mapping_list = map(range(len(l:key_mapping)), { index, val -> l:key_mapping[val] })
```
#### 1文字ずつ処理
```
for c in split("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_.", '\zs')
...
endfor
```
#### slice
最初から最後の1文字手前まで
```
'sample'[:-2]
```
最後の文字のみを取得
```
'sample'[-1:]
```
#### 繰り返し文字連結
`repeat(char, num)`
#### マルチバイトな文字列の長さ
[文字列型 — 名無しのvim使い]( http://nanasi.jp/articles/code/variable/string.html )
``` vim
strlen(substitute("マルチバイトな日本語文字列", ".", "x", "g"))
# lambda function for multi bytes string
let Mlen = { s -> strlen(substitute(s, ".", "x", "g"))}
```
### mapの注意点
`map`を使用すると第一引数のlistの中身自体が書き換わる(`+[]`でコピーを作成することができる)
``` vim
let include_dirs=['a','b','c']
echo include_dirs
let include_dirs_opts=map(include_dirs+[], {k,v -> '-I'.v})
echo include_dirs
```
### 検索
last searched pattern
```
@/
```
### 以前に開いたときのファイルのカーソル位置取得
``` vim
getpos("'`")
```
### 禁止行為
`<expr>`指定時に`setline()`を呼んではならない
``` vim
function! s:UnTab()
let line = getline('.')
if line[0] == "\t"
echom 'success'
let line = line[1:]
call setline('.', line)
endif
return ''
endfunction
inoremap <expr><S-Tab> pumvisible() ? "\<C-p>" : <SID>UnTab()
```
`<C-o>`の影響で`pumvisible()`は常にゼロ
``` vim
# ng
inoremap <S-Tab> <C-o>:echo pumvisible()<CR>
# ok
inoremap <S-Tab> <C-r>=<SID>UnTab()<CR>
```
`:normal` in `<expr>` is NG
## lua
[nvim-lua-guide-ja/README.ja.md at master · willelz/nvim-lua-guide-ja]( https://github.com/willelz/nvim-lua-guide-ja/blob/master/README.ja.md )
### luaからvimの変数を参照する
[nvim-lua-guide-ja/README.ja.md at master · willelz/nvim-lua-guide-ja]( https://github.com/willelz/nvim-lua-guide-ja/blob/master/README.ja.md#%E3%83%A1%E3%82%BF%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B5%E3%83%BC%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B-1 )
## リモート
### scpプロトコルでのリモートファイル編集
`:e scp://x.x.x.x//Users/xxx/tmp/README.md`
* `~`は使えない
* リモートのファイル編集時に無理やりsudoして保存する方法は使えないことに注意
* ホームディレクトリからの相対パスとする場合は`/`を先頭につける必要がない
## Neovim
### Vim scriptでのバージョン確認
``` vim
:echo has('nvim')
:echo has('nvim-0.1')
:echo has('nvim-0.1.6')
```
### 色付きのメッセージを簡単に出力する
``` vim
lua vim.api.nvim_echo({{"This is a "}, {"warning", "WarningMsg"}, {" message.\n"}, {"NOTE: This is a comment.", "Comment"}, }, true, {})
call nvim_echo([["This is a "], ["warning", "WarningMsg"], [" message.\n"], ["NOTE: This is a comment.", "Comment"], ], v:true, {})
```
## Plugin
### 誰かのライブラリを拡張(ハック)する
[Big Sky :: 他人が作ったVimScriptを一切触らず拡張する]( https://mattn.kaoriya.net/software/vim/20110728094347.htm )
### 多重ロード防止
`plugin`ディレクトリ:`!`あり
``` vim
if !exists('g:loaded_hoge')
finish
endif
let g:loaded_hoge = 1
```
`autoload`ディレクトリ:`!`なし
``` vim
if exists('g:loaded_hoge')
finish
endif
let g:loaded_hoge = 1
```
### [fatih/vim\-go: Go development plugin for Vim]( https://github.com/fatih/vim-go )
* `:GoFillStruct`: 構造体のフィールドを自動生成する
### [ripxorip/aerojump\.nvim: Aerojump is a fuzzy\-match searcher/jumper for Neovim with the goal of quick keyboard navigation]( https://github.com/ripxorip/aerojump.nvim )
入力文字を利用して、コードの移動を容易にする
### [Shougo/neosnippet\.vim: neo\-snippet plugin]( https://github.com/Shougo/neosnippet.vim )
* [記号の後ろだと補完が出来ない · Issue \#444 · Shougo/neosnippet\.vim]( https://github.com/Shougo/neosnippet.vim/issues/444 )
* 仕様である
### [nvim\-treesitter/nvim\-treesitter: Nvim Treesitter configurations and abstraction layer]( https://github.com/nvim-treesitter/nvim-treesitter )
* Neovimには[neovim/runtime/lua/vim/treesitter]( https://github.com/neovim/neovim/tree/bb7ed42089e77feebe26b94f4cb46c72254b55e6/runtime/lua/vim/treesitter )にて、Tree-sitterのランタイムを制御するコードが組み込まれているが、パーサーなどの制御のためにこのプラグインが必要となる
* カラースキームをこのプラグインに対応しているものに変更しないと恩恵を受けることができないことに注意
また、[airblade/vim\-gitgutter: A Vim plugin which shows git diff markers in the sign column and stages/previews/undoes hunks and partial hunks\.]( https://github.com/airblade/vim-gitgutter )と組み合わせた際に、例えば、`GitGutterAddLine`などは`DiffAdd`へひも付くので、その行の背景色がすべて上書きされてしまうので、独自に設定を上書きする必要があることに注意
## デバッグ
エラー発生時に`v:exception`, `v:throwpoint`を確認するとよい
## Tips
### 検索
`:set smartcase`利用時でも`\C`を先頭に付与すると、厳密に大文字小文字を区別するようになる
### visual mode
`gv`: reselect the last block
### insert modeから素早くvisual modeへ移動
`<C-o>v`
### visual modeのカーソル位置
* `o`: toggle
* `` `< ``: 先頭
* `` `> ``: 末尾
### 繰り返し文字列挿入
* normal modeで`数字i入力したい文字列`+`Esc`とすると入力できるが,多少タイムラグがある
* insert modeで文字を入力してから,normal modeになり,`数字.`の方はタイムラグがない
### エラーコードで終了
例えば、gitのcommit message用のエディタとして起動している時に利用する
```
:cq[uit]
```
## トラブルシューティング
### golangの補完が機能しない
[fatih/vim\-go: Go development plugin for Vim]( https://github.com/fatih/vim-go )
`:GoUpdateBinaries`を実行する
### rustの補完が機能しない
``` bash
rustup update
rustup component add rls-preview --toolchain nightly
rustup component add rust-analysis --toolchain nightly
rustup component add rust-src --toolchain nightly
```
### kotlinの補完が機能しない
一度、該当のリポジトリでビルドをしておくこと
``` bash
./gradlew build
```
### vimのフォーマッターがない
現時点でまともなものは存在しない
[Vim Script Parser written in Go \- haya14busa \- Medium]( https://medium.com/@haya14busa/vim-script-parser-written-in-go-4d0296782a14 )
> I’ll try to develop vimfmt, Vim script version of gofmt, by using go-vimlparser.
[add a formatter for vimscript · Issue \#23 · google/vim\-codefmt]( https://github.com/google/vim-codefmt/issues/23 )
### 🔥autocmdでトリガーされた処理で他のautocmdがトリガーされない
[++nested]( https://vim-jp.org/vimdoc-ja/autocmd.html#autocmd-nested )
> 既定では、自動コマンドはネストしない (入れ子にならない)。例えば、自動コマンド
内で ":e" や ":w" を使っても、これらに対してはイベント BufRead や BufWrite に
よる自動コマンドは実行されない。もしこれを実行してほしいなら、ネストしてほしい
コマンド内でフラグ "nested" を使うこと。
\ No newline at end of file
[[_TOC_]]
## :bulb:how to update plugins
```bash
brew upgrade nvim
pip install pynvi
pip install neovim
```
```vim
:PlugUpdate
:TSInstall all
:TSUpdate
:checkhealth
:checkhealth nvim-treesitter
```
* エラーが発生した場合は、GitHubで該当するpluginのissueを探す
* pluginのon/offを試してみる
e.g.
* [nvim-treesitterで「query: invalid node type at...」エラーが出た #neovim - Qiita](https://qiita.com/ZOI_dayo/items/3c39252c729dd27393f3)
* [Highlights broken after update with `query: invalid structure` · Issue #3092 · nvim-treesitter/nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter/issues/3092)
## オレオレコードリーディングチートシート
マッピング
* S: 関数やシンボルなどの一覧を表示して飛ぶ
* \_: 型の定義へ飛ぶ
* H: 型やメソッドの情報を表示
* K: 定義へ飛ぶ
* R: 利用されている箇所の一覧して飛ぶ
コマンド
* FZFbuffers: バッファ一覧を表示して切り替え
* RenameRefactor: 変数名などを一括変更する
fzf
* L: 行を検索する
### マークダウン
* `:Unite outline`: 見出しジャンプ
### 移動
* `g<space>` + 2文字入力: 画面内移動
* `[`,`]`: 関数ごとにジャンプ
* `{`,`}`: ブロック?ごとにジャンプ
* [stevearc/aerial.nvim: Neovim plugin for a code outline window](https://github.com/stevearc/aerial.nvim#keymaps)
* `AerialToggle`: 関数などのシンボルを一覧表示してジャンプ可能
* 自作ショートカットでは`<Leader>A``AerialOpen`
### ショートカットメモ
* [tpope/vim-abolish: abolish.vim: easily search for, substitute, and abbreviate multiple variants of a word](https://github.com/tpope/vim-abolish)
```vim
" crs "SnakeCase" -> "snake_case"
" crm "mixed_case" -> "MixedCase"
" crc "camel_case" -> "camelCase"
" cru "upper_case" -> "UPPER_CASE"
call extend(Abolish.Coercions, { 'c': Abolish.camelcase,
\ 'm': Abolish.mixedcase,
\ 's': Abolish.snakecase,
\ '_': Abolish.snakecase,
\ 'u': Abolish.uppercase,
\ 'U': Abolish.uppercase,
\ '-': Abolish.dashcase,
\ 'k': Abolish.dashcase,
\ '.': Abolish.dotcase,
\ ' ': Abolish.spacecase,
\ 't': Abolish.titlecase,
\ "function missing": s:function("s:unknown_coercion")
\}, "keep")
```
## how to build vim
[vim-jp » Linuxでのビルド方法](https://vim-jp.org/docs/build_linux.html)
<details>
<summary>how to build</summary>
<!--you must insert blank line-->
\`\`\` bash $ git clone https://github.com/vim/vim.git $ cd vim $ ./configure --with-features=huge \\ --enable-multibyte \\ --enable-fontset \\ --enable-fail-if-missing \\ --prefix=$HOME/local \\ --enable-pythoninterp=yes \\ --enable-python3interp=yes $ make -j8 $ ./src/vim --version VIM - Vi IMproved 8.2 (2019 xxx, compiled xxx) Included patches: 1-19 Compiled by xxx Huge version with GTK2 GUI. Features included (+) or not (-): +acl -farsi -mouse_sysmouse -tag_old_static +arabic +file_in_path +mouse_urxvt -tag_any_white +autocmd +find_in_path +mouse_xterm -tcl +autochdir +float +multi_byte +termguicolors -autoservername +folding +multi_lang +terminal +balloon_eval -footer -mzscheme +terminfo +balloon_eval_term +fork() +netbeans_intg +termresponse +browse +gettext +num64 +textobjects ++builtin_terms -hangul_input +packages +textprop +byte_offset +iconv +path_extra +timers +channel +insert_expand -perl +title +cindent +job +persistent_undo +toolbar +clientserver +jumplist +popupwin +user_commands +clipboard +keymap +postscript +vartabs +cmdline_compl +lambda +printer +vertsplit +cmdline_hist +langmap +profile +virtualedit +cmdline_info +libcall +python/dyn +visual +comments +linebreak +python3/dyn +visualextra +conceal +lispindent +quickfix +viminfo +cryptv +listcmds +reltime +vreplace +cscope +localmap +rightleft +wildignore +cursorbind -lua -ruby +wildmenu +cursorshape +menu +scrollbind +windows +dialog_con_gui +mksession +signs +writebackup +diff +modify_fname +smartindent +X11 +digraphs +mouse -sound -xfontset +dnd +mouseshape +spell +xim -ebcdic +mouse_dec +startuptime -xpm +emacs_tags -mouse_gpm +statusline +xsmp_interact +eval -mouse_jsbterm -sun_workshop +xterm_clipboard +ex_extra +mouse_netterm +syntax -xterm_save +extra_search +mouse_sgr +tag_binary system vimrc file: "$VIM/vimrc" user vimrc file: "$HOME/.vimrc" 2nd user vimrc file: "\~/.vim/vimrc" user exrc file: "$HOME/.exrc" system gvimrc file: "$VIM/gvimrc" user gvimrc file: "$HOME/.gvimrc" 2nd user gvimrc file: "\~/.vim/gvimrc" defaults file: "$VIMRUNTIME/defaults.vim" system menu file: "$VIMRUNTIME/menu.vim" fall-back for $VIM: "\~/local/share/vim" Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H -DFEAT_GUI_GTK -pthread -I\~/.linuxbrew/Cellar/pcre/8.42/include -I\~/.linuxbrew/Cellar/expat/2.2.6/include -I/usr/include/gtk-2.0 -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include -I/usr/include/gio-unix-2.0/ -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/libpng12 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/freetype2 -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 Linking: gcc -L/usr/local/lib -Wl,--as-needed -o vim -lgtk-x11-2.0 -lgdk-x11-2.0 -lpangocairo-1.0 -latk-1.0 -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lpangoft2-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lfontconfig -lfreetype -lSM -lICE -lXt -lX11 -lXdmcp -lSM -lICE -lm -ltinfo -lnsl -lacl -lattr -ldl \`\`\`
</details>
## how to name plugins
* `*.vim`
* `vim-*`
## Vim script
### snippet
#### visualモードで選択しているテキスト操作
[vim - How to get visually selected text in VimScript - Stack Overflow](https://stackoverflow.com/questions/1533565/how-to-get-visually-selected-text-in-vimscript)
```vim
function! s:get_visual_selection()
" Why is this not a built-in Vim script function?!
let [line_start, column_start] = getpos("'<")[1:2]
let [line_end, column_end] = getpos("'>")[1:2]
let lines = getline(line_start, line_end)
if len(lines) == 0
return ''
endif
let lines[-1] = lines[-1][: column_end - (&selection == 'inclusive' ? 1 : 2)]
let lines[0] = lines[0][column_start - 1:]
return join(lines, "\n")
endfunction
function! s:delete_visual_selection()
let selected = s:get_visual_selection()
call setpos('.', getpos("'<"))
let Mlen = { s -> strlen(substitute(s, ".", "x", "g"))}
let l = Mlen(selected)
if l > 0
execute "normal! v".(l-1)."\<Right>\"_x"
endif
return selected
endfunction
```
#### 特定行に内容をセットする
```vim
function! s:setlines(pos, lines)
if len(a:lines)==0
execute ':'.a:pos.'d'
return
endif
call setline(a:pos, a:lines[0])
call append(a:pos, a:lines[1:])
endfunction
```
#### 範囲選択コマンド
```vim
function! XXX() range
for n in range(a:firstline, a:lastline)
let line = getline(n)
endfor
endfunction
command! -range XXX <line1>,<line2>call XXX()
```
#### 外部コマンド
[vim-clang-format/clang_format.vim at master · rhysd/vim-clang-format](https://github.com/rhysd/vim-clang-format/blob/master/autoload/clang_format.vim#L14)
```vim
function! s:has_vimproc() abort
if !exists('s:exists_vimproc')
try
silent call vimproc#version()
let s:exists_vimproc = 1
catch
let s:exists_vimproc = 0
endtry
endif
return s:exists_vimproc
endfunction
function! s:success() abort
let l:exit_success = (s:has_vimproc() ? vimproc#get_last_status() : v:shell_error) == 0
return l:exit_success
endfunction
function! s:error_message(result) abort
echohl ErrorMsg
echomsg 'xxx has failed to yyy.'
for l:line in split(a:result, "\n")[0:1]
echomsg l:line
endfor
echohl None
endfunction
```
### 行継続時のコメント
```vim
let hoge = {
\ "a": 1,
"\ comment \の後に必ずスペースを入れること
\ "b": 2
\ }
```
[Twitter](https://twitter.com/Bakudankun/status/1334618416951463937)
### [実は必要のないset nocompatible](https://github.com/vim-jp/reading-vimrc/wiki/vimrc%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3#%E5%AE%9F%E3%81%AF%E5%BF%85%E8%A6%81%E3%81%AE%E3%81%AA%E3%81%84set-nocompatible)
### 他のバッファの行数のみを知りたいが,vim単体では行全体を取得してから長さ取得となる
[Is there a way to get the number of lines of a buffer in Vim Script? - Stack Overflow](https://stackoverflow.com/questions/14544618/is-there-a-way-to-get-the-number-of-lines-of-a-buffer-in-vim-script)
### sortしたい
```vim
# builtin command
:{range}sort
# unix command
:{range}!sort
```
### expand - スクリプトのディレクトリ自体を取得する
[Vimスクリプトでスクリプトのディレクトリを取得する -- ぺけみさお](https://www.xmisao.com/2014/05/28/vim-get-script-path.html)
### match, 2match, 3match
[pattern - Vim日本語ドキュメント](https://vim-jp.org/vimdoc-ja/pattern.html#:2match)
prefixがつくと別々の独立したマッチを行う
[nvim-treesitter/nvim-treesitter: Nvim Treesitter configurations and abstraction layer](https://github.com/nvim-treesitter/nvim-treesitter)有効時には`2match``3match`で設定しないとハイライトされないことに注意
`matchadd`関数を利用すると各ウィンドウごとに確実にシンタックスハイライトが可能となる
### visual mode
#### 矩形選択(ctrl-v)
[visual - Vim日本語ドキュメント](https://vim-jp.org/vimdoc-ja/visual.html#CTRL-V)
> WindowsではCTRL-Vはテキストの貼り付けにマップされることがあり、その際にはビジュアルモードを開始できない。[CTRL-V-alternative](https://vim-jp.org/vimdoc-ja/gui_w32.html#CTRL-V-alternative) を参照。
> CTRL-Vがペーストに使われてしまうので、矩形ビジュアル選択を開始することができな い。これにはCTRL-Qを代用できる。
#### `'<,'>` range機能
行単位(~~文字単~~)
#### [visualモードで選択した範囲に含まれる「行」ではなく、選択した「テキスト」にだけ置換処理を適用する。 — 名無しのvim使い](http://nanasi.jp/articles/howto/editing/replace-selecttext.html)
置換対象の先頭に`\%V`を付加する
### visual modeの種類を判定したい
`visualmode()` `v`,`V`,`^V`?
#### [ビジュアルモードの選択情報の取得 — 名無しのvim使い](http://nanasi.jp/articles/code/screen/visual.html)
```vim
:let tmp = @@
:silent normal gvy
:let selected = @@
:let @@ = tmp
:echo selected
```
#### visual mode時に関数を呼びたい
```vim
vnoremap :<C-u>call xxx<CR>
```
`<C-u>`でrangeを無効化
[vimrcでのキーマッピングの際の意味 - e_v_e’s blog](http://e-v-e.hatenablog.com/entry/20150101/1420067539)
### cmdline mode判定
`getcmdtype()`
```
> debug mode command |debug-mode|
/ forward search command
? backward search command
@ |input()| command
- |:insert| or |:append| command
= |i_CTRL-R_=|
```
### 無名バッファを開いてpasteしたい
e.g. paste z regster
```vim
tabnew | exe "normal! \"zp"
```
### 編集しても:qで警告なしに終了可能なバッファにしたい
```vim
:setlocal buftype=nofile
```
### get window width
[Get "usable" window width in vim script - Stack Overflow](https://stackoverflow.com/questions/26315925/get-usable-window-width-in-vim-script)
```vim
:set virtualedit=all
:norm! g$
:echo virtcol('.')
```
### original commandに`-bar`オプションがない場合
wrapperを定義すれば良い
```vim
autocmd BufWritePre *.go if IsAutoFormat() | :GoFmtWrapper | endif
" NOTE: original GoFmt has no '-bar' option
command! -bar GoFmtWrapper :GoFmt
```
### `range`なfunctionを他のcommandとしてではなくfunctionとして呼びたい
[vimscript - Run global with range from within function - Vi and Vim Stack Exchange](https://vi.stackexchange.com/questions/9037/run-global-with-range-from-within-function)
```vim
4,8call Function()
```
### メッセージに出力する形式での変数の値確認
`echom string(xxx)`とすると`echo`のように任意の型に対して利用できる
### コマンドのログ付き実行
`:99verbose COMMAND`
### 行操作
```vim
setline()
append()
" NOTE: 対象がfoldされているとすべて消える
execute 'normal! "_dd'
# 現在の見ている範囲
let topline = line("w0")
let bottomline = line("w$")
let lastline = line("$")
```
#### 現在位置に挿入
```vim
call setline('.', line[:col('.')-1] . repeat(' ', &tabstop) . line[col('.'):])
call cursor('.', col('.')+&tabstop)
```
[vimscript - How can I append text to the current line? - Vi and Vim Stack Exchange](https://vi.stackexchange.com/questions/12445/how-can-i-append-text-to-the-current-line)
### source
#### 実はURLを指定してファイルを読み込むことができる
とある環境の内部では`wget`が実行されていた
e.g. `source https://raw.githubusercontent.com/mhinz/vim-galore/master/static/minimal-vimrc.vim`
#### sourceしたvimファイル中での早期return
`finish`
### 関数内で関数定義可能
e.g. [vim-codefmt/yapf.vim at 5ede026bb3582cb3ca18fd4875bec76b98ce9a12 · google/vim-codefmt](https://github.com/google/vim-codefmt/blob/5ede026bb3582cb3ca18fd4875bec76b98ce9a12/autoload/codefmt/yapf.vim#L28)
### コマンド
#### `<Plug>`なキーマップをコマンドから呼びたい
[Vim の \<Plug\> ってなんだ? - Qiita](https://qiita.com/domodomodomo/items/043e1f8d0f2a08ad0c53)
`command! PreviewGitDiff call feedkeys("\<Plug>(GitGutterPreviewHunk)")`
### キーマップ
[Mapping keys in Vim - Tutorial (Part 1) | Vim Tips Wiki | FANDOM powered by Wikia](http://vim.wikia.com/wiki/Mapping_keys_in_Vim\_-\_Tutorial\_(Part_1)) `<sciprt>`を付加すると意図しない上書きを禁止しやすい
> The following characters may be displayed before the {rhs} of the map:
```
* The {rhs} of the map is not re-mappable. Defined using the
':noremap' or ':nnoremap' or ':inoremap', etc. commands.
& Only script local mappings are re-mappable in the {rhs} of the
map. The map command has the <script> attribute.
@ A buffer local map command with the <buffer> attribute.
```
#### 割当不可
* `ctrl-;`,`ctrl-:`
* `ctrl-,`,`ctrl-.`
* `<S-Space>`
* `<C-S-xxx>`
`inoremap``<ESC>`をマッピングすると、矢印移動でABCDが入力される問題が発生する
#### `<C-u>`
`nnoremap <Space>w :<C-u>w<CR>``<C-u>`は範囲指定の数字を削除するため
#### 特定のキーがマッピングされているかどうか
```vim
maparg('hoge')
maparg('<S-Tab>', 'i')
!empty(maparg('hoge'))
```
### 判定
#### 関数の存在判定
[vim - VimL: Checking if function exists - Stack Overflow](https://stackoverflow.com/questions/13710364/viml-checking-if-function-exists)
* `"`で囲むこと
* `*`を付加すること
```vim
if exists("*GitBranchInfoString")
" do stuff here
endif
```
#### 関数が定義されているファイルを調べる
`:verbose function /FunctionNameRegex/`
#### vimコマンドの判定
`exists(":HogeCommand")`
注意点: help existsより、完全一致の場合は2が返されるが、完全一致せずに、`:HogeCommandPlus`にマッチした場合は1となる
```
1 for match with start of a command
2 full match with a command
3 matches several user commands
To check for a supported command always check the return value to be 2.
```
#### プラグインの読み込み判定
```vim
if &rtp =~ 'plugin-name'
...
endif
```
```vim
if &rtp !~ 'non-exist-plugin-name'
...
endif
```
[Vim script の exists で autoload の関数は判定してはいけない - C++でゲームプログラミング](http://d.hatena.ne.jp/osyo-manga/20120412/1334158849)
#### 変数の存在判定
`exists('v:t_number')`
#### type detection
`:h type()`
### autocmd
* [autocmd-once](https://vim-jp.org/vimdoc-en/autocmd.html#autocmd-once)
* one-shotなイベント向け
* [autocmd-nested](https://vim-jp.org/vimdoc-en/autocmd.html#autocmd-nested)
* autocmdトリガー中に他のautocmdのトリガー向けに意図的にイベントの発生を許容してネストさせる
### runtime
```vim
runtime! xxx/yyy/zzz/*.vim
```
ではパスが適切でなくともエラーが表示されないので注意
### execute
* `call execute("echo 42")`: 出力されない
* `echo execute("echo 42")`: 出力される
* `call execute("echo 42", "")`: 出力される
### 変数のプリフィックス
* `l:`: ローカル変数(関数内部のデフォルト接頭辞であるので、省略可)
* `g:`: グローバル変数(関数外の場合のデフォルト)
* `v:`: 特殊な変数のみ
* `b:`: バッファローカル
* 新規バッファになったときに,autocmd系から呼ばれるときにも初期化された状態となる
* `w:`: ウィンドウローカル
* `t:`: タブローカル
* `s:`: スクリプトローカル
#### バッファローカルな変数を利用して状態を保持したい
単純に`.vimrc`に定義を書いた場合には、単に最初のバッファのみに実体が生成されるだけで、他のバッファを開いたときにその変数の値を読み込もうとするとエラーとなるので、その変数を利用する関数内の先頭などで下記のようにデフォルト値を設定する必要がある
```vim
let b:hoge = get(b:, 'hoge', 'default value')
```
### 正規表現
* `\+`
* `\(`,`\)`
* `^`,`$`,`.`
* `*`:最長マッチ
* `\{-}`:最短マッチ
* `\zs`:どこにでもマッチしてマッチの開始地点を設定する
### for
```vim
for l:n in range(0, 10)
endfor
```
```vim
for l:val in l:list
endfor
```
```vim
for l:key in keys(l:map)
let l:val = l:map[l:key]
endfor
```
### filename
* 現在のファイルを対象:`expand`
* 変数を対象:`fnamemodify`
### save & restore settings
#### cursor
```
let l:view = winsaveview()
...
silent call winrestview(l:view)
```
#### window
```
let save_winnr = winnr()
...
exe save_winnr. 'wincmd w'
```
#### user setting
```
" push user setting
let s:save_cpo = &cpo
set cpo&vim
" write plugin script here
" pop user setting
let &cpo = s:save_cpo
unlet s:save_cpo
```
### insert modeからcommand line modeへ移動する例
* `<ESC>:xxx<CR>i`:カーソルがずれる
* `<C-o>:xxx<CR>`:カーソルがずれない
### vimscriptの実行結果を変数に格納して、その変数を外部コマンドへパイプする例
```
silent! redir => commands
silent! scriptnames
silent! redir END
echo(system('grep ".vim"', commands))
```
### multiple filetype
通常,使えない [Multiple file types in vim - Stack Overflow](https://stackoverflow.com/questions/2601403/multiple-file-types-in-vim)
> ou can specify to use multiple filetypes at the same time. For example: :setfiletype html.php But most of filetype plugings and syntax files are not designed for such cases. See also :help 'filetype'
[複数の'filetype'を扱いたい · Issue #1034 · vim-jp/issues](https://github.com/vim-jp/issues/issues/1034)
### exit code
`v:shell_error`
### 文字列処理
#### 文字列の文字を配列の要素とする
e.g. `"abc" -> ['a', 'b', 'c']`
```
let l:key_mapping = "asdfghjklzxcvbnmqwertyuiop"
let g:key_mapping_list = map(range(len(l:key_mapping)), { index, val -> l:key_mapping[val] })
```
#### 1文字ずつ処理
```
for c in split("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_.", '\zs')
...
endfor
```
#### slice
最初から最後の1文字手前まで
```
'sample'[:-2]
```
最後の文字のみを取得
```
'sample'[-1:]
```
#### 繰り返し文字連結
`repeat(char, num)`
#### マルチバイトな文字列の長さ
[文字列型 — 名無しのvim使い](http://nanasi.jp/articles/code/variable/string.html)
```vim
strlen(substitute("マルチバイトな日本語文字列", ".", "x", "g"))
# lambda function for multi bytes string
let Mlen = { s -> strlen(substitute(s, ".", "x", "g"))}
```
### mapの注意点
`map`を使用すると第一引数のlistの中身自体が書き換わる(`+[]`でコピーを作成することができる)
```vim
let include_dirs=['a','b','c']
echo include_dirs
let include_dirs_opts=map(include_dirs+[], {k,v -> '-I'.v})
echo include_dirs
```
### 検索
last searched pattern
```
@/
```
### 以前に開いたときのファイルのカーソル位置取得
```vim
getpos("'`")
```
### 禁止行為
`<expr>`指定時に`setline()`を呼んではならない
```vim
function! s:UnTab()
let line = getline('.')
if line[0] == "\t"
echom 'success'
let line = line[1:]
call setline('.', line)
endif
return ''
endfunction
inoremap <expr><S-Tab> pumvisible() ? "\<C-p>" : <SID>UnTab()
```
`<C-o>`の影響で`pumvisible()`は常にゼロ
```vim
# ng
inoremap <S-Tab> <C-o>:echo pumvisible()<CR>
# ok
inoremap <S-Tab> <C-r>=<SID>UnTab()<CR>
```
`:normal` in `<expr>` is NG
## lua
[nvim-lua-guide-ja/README.ja.md at master · willelz/nvim-lua-guide-ja](https://github.com/willelz/nvim-lua-guide-ja/blob/master/README.ja.md)
### luaからvimの変数を参照する
[nvim-lua-guide-ja/README.ja.md at master · willelz/nvim-lua-guide-ja](https://github.com/willelz/nvim-lua-guide-ja/blob/master/README.ja.md#%E3%83%A1%E3%82%BF%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B5%E3%83%BC%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B-1)
## リモート
### scpプロトコルでのリモートファイル編集
`:e scp://x.x.x.x//Users/xxx/tmp/README.md`
* `~`は使えない
* リモートのファイル編集時に無理やりsudoして保存する方法は使えないことに注意
* ホームディレクトリからの相対パスとする場合は`/`を先頭につける必要がない
## Neovim
### Vim scriptでのバージョン確認
```vim
:echo has('nvim')
:echo has('nvim-0.1')
:echo has('nvim-0.1.6')
```
### 色付きのメッセージを簡単に出力する
```vim
lua vim.api.nvim_echo({{"This is a "}, {"warning", "WarningMsg"}, {" message.\n"}, {"NOTE: This is a comment.", "Comment"}, }, true, {})
call nvim_echo([["This is a "], ["warning", "WarningMsg"], [" message.\n"], ["NOTE: This is a comment.", "Comment"], ], v:true, {})
```
## Plugin
### 誰かのライブラリを拡張(ハック)する
[Big Sky :: 他人が作ったVimScriptを一切触らず拡張する](https://mattn.kaoriya.net/software/vim/20110728094347.htm)
### 多重ロード防止
`plugin`ディレクトリ:`!`あり
```vim
if !exists('g:loaded_hoge')
finish
endif
let g:loaded_hoge = 1
```
`autoload`ディレクトリ:`!`なし
```vim
if exists('g:loaded_hoge')
finish
endif
let g:loaded_hoge = 1
```
### [fatih/vim-go: Go development plugin for Vim](https://github.com/fatih/vim-go)
* `:GoFillStruct`: 構造体のフィールドを自動生成する
### [ripxorip/aerojump.nvim: Aerojump is a fuzzy-match searcher/jumper for Neovim with the goal of quick keyboard navigation](https://github.com/ripxorip/aerojump.nvim)
入力文字を利用して、コードの移動を容易にする
### [Shougo/neosnippet.vim: neo-snippet plugin](https://github.com/Shougo/neosnippet.vim)
* [記号の後ろだと補完が出来ない · Issue #444 · Shougo/neosnippet.vim](https://github.com/Shougo/neosnippet.vim/issues/444)
* 仕様である
### [nvim-treesitter/nvim-treesitter: Nvim Treesitter configurations and abstraction layer](https://github.com/nvim-treesitter/nvim-treesitter)
* Neovimには[neovim/runtime/lua/vim/treesitter](https://github.com/neovim/neovim/tree/bb7ed42089e77feebe26b94f4cb46c72254b55e6/runtime/lua/vim/treesitter)にて、Tree-sitterのランタイムを制御するコードが組み込まれているが、パーサーなどの制御のためにこのプラグインが必要となる
* カラースキームをこのプラグインに対応しているものに変更しないと恩恵を受けることができないことに注意
また、[airblade/vim-gitgutter: A Vim plugin which shows git diff markers in the sign column and stages/previews/undoes hunks and partial hunks.](https://github.com/airblade/vim-gitgutter)と組み合わせた際に、例えば、`GitGutterAddLine`などは`DiffAdd`へひも付くので、その行の背景色がすべて上書きされてしまうので、独自に設定を上書きする必要があることに注意
## デバッグ
エラー発生時に`v:exception`, `v:throwpoint`を確認するとよい
## Tips
### 検索
`:set smartcase`利用時でも`\C`を先頭に付与すると、厳密に大文字小文字を区別するようになる
### visual mode
`gv`: reselect the last block
### insert modeから素早くvisual modeへ移動
`<C-o>v`
### visual modeのカーソル位置
* `o`: toggle
* `` `< ``: 先頭
* `` `> ``: 末尾
### 繰り返し文字列挿入
* normal modeで`数字i入力したい文字列`+`Esc`とすると入力できるが,多少タイムラグがある
* insert modeで文字を入力してから,normal modeになり,`数字.`の方はタイムラグがない
### エラーコードで終了
例えば、gitのcommit message用のエディタとして起動している時に利用する
```
:cq[uit]
```
## トラブルシューティング
### golangの補完が機能しない
[fatih/vim-go: Go development plugin for Vim](https://github.com/fatih/vim-go)
`:GoUpdateBinaries`を実行する
### rustの補完が機能しない
```bash
rustup update
rustup component add rls-preview --toolchain nightly
rustup component add rust-analysis --toolchain nightly
rustup component add rust-src --toolchain nightly
```
### kotlinの補完が機能しない
一度、該当のリポジトリでビルドをしておくこと
```bash
./gradlew build
```
### vimのフォーマッターがない
現時点でまともなものは存在しない
[Vim Script Parser written in Go - haya14busa - Medium](https://medium.com/@haya14busa/vim-script-parser-written-in-go-4d0296782a14)
> I’ll try to develop vimfmt, Vim script version of gofmt, by using go-vimlparser.
[add a formatter for vimscript · Issue #23 · google/vim-codefmt](https://github.com/google/vim-codefmt/issues/23)
### :fire:autocmdでトリガーされた処理で他のautocmdがトリガーされない
[++nested](https://vim-jp.org/vimdoc-ja/autocmd.html#autocmd-nested)
> 既定では、自動コマンドはネストしない (入れ子にならない)。例えば、自動コマンド 内で ":e" や ":w" を使っても、これらに対してはイベント BufRead や BufWrite に よる自動コマンドは実行されない。もしこれを実行してほしいなら、ネストしてほしい コマンド内でフラグ "nested" を使うこと。
\ No newline at end of file