clang-renameをVimからサクッと呼び出してC++のリネームを快適にする。
最近Go言語を使ってるんですが、この言語gofmt
やgorename
、goimports
などのツールが充実していて良いですね。
C系の言語にも同じようなツールは存在します。
Welcome to Extra Clang Tools’s documentation! — Extra Clang Tools 5 documentation
この内clang-format
は既にVimプラグインが存在します。
C や C++ のコードを自動で整形する clang-format を Vim で - はやくプログラムになりたい
今回はclang-rename
のVimプラグインを作りました。
clang-rename
は識別子をリネームするツールです。
clang-renameの導入
Arch
公式リポジトリからclang-tools-extra
を入れましょう。
Ubuntu
clang-3.5
以上のバージョンに含まれています。
ただしclang-rename
のバージョンが古いと後述のqualified name
機能が使えません。
この機能を使いたい場合はPPAなどからの導入を検討してください。
clang-rename --help
で-qualified-name
が表示されれば大丈夫です。
使い方
単一ファイルの場合:ClangRenameCurrent
か:ClangRenameQualifiedName
を使えば用が済むでしょう。
{new_name}
を省略した場合は入力プロンプトが表示されます。
ClangRenameOffset [{offset} [{new_name}]]
オフセットを指定してリネームします。
例えばファイルの先頭のオフセットは0です。
-1
を指定すると現在のカーソル位置をオフセットとして扱います。
ClangRenameCurrent [{new_name}]
カーソル位置のシンボル名を変更します。
内部でClangRenameOffset
を実行しています。
ClangRenameQualifiedName [{qualified_name} [{new_name}]]
シンボル名を指定してリネームします。
このコマンドを使うにはclang-rename
が-qualified-name
オプションをサポートしている必要があります。
ClangRename [...]
引数によって動作が変わります。
0個か1個ならClangRenameCurrent
が実行されます。
2個ならClangRenameQualifiedName
が実行されます。
その他
<Plug>(clang_rename-current)
ClangRenameCurrent
のキーマップg:clang_rename#flags
clang-rename
の引数g:clang_rename#compile_flags
clang-rename
が解析するときに使うコンパイルオプション(-std=c++11
とか)
終わりに
実はclang extra tools
には標準でVimとEmacs向けのスクリプトが付属してます。
ですが、微妙に使いづらかったので、このプラグインを作りました。
vim-fakearray ダミー配列を手軽に入力するプラグイン作った
プログラミングをしていると適当な配列が欲しい時ありますよね。
「0〜100の整数からランダムに10個選んだ配列」などなど。
そんなVimmerの要望を叶えるのがvim-fakearrayです。
vim-fakearrayはvim-fakeに依存しています。
vim-fakeについては作者の記事を参考にしてください。
qiita.com
インサートモードに<Plug>(fakearray)
のキーマップを割り当てれば、
プロンプトを呼び出してダーミー配列を手軽に挿入できます。
解説
呼び出し階層
<Plug>(fakearray)
→ fakearray#gen
→ fakearray#val
→ fake#gen
|fake#int
|fake#float
|fake#chars
fakearray#val
fakearray#val(first, second)
は引数によって呼び出すfake#
関数を変えます。
first | second | 呼び出し |
---|---|---|
整数 | 整数 | fake#int(first, second) |
少数or整数 | 少数or整数 | fake#float(first, second) |
文字列 | 整数 | fake#chars(fake#int(1, second), first) |
文字列 | 空文字列 '' |
fake#gen(first) |
fake#int fake#float
この2つは第1引数〜第2引数の範囲の値を返しますが、Vimのバージョンによっては正しく動作しないようです。
恐らくVimが内部で扱う整数のサイズに依存しているのでしょう。
64bit整数が追加されたのは7.4.1976のようです。
Vim8.0とNeovim0.2では正常に動作しました。
fake#chars
第1引数は生成する文字数です。
第2引数は'abc'
のような適当な文字列の他に、'\w'
などの文字セットを使うことが出来ます。
詳細はvim-fakeのドキュメントを見てください。
fake#gen
'job'
、'country'
、'word'
などのカテゴリを渡すことが出来ます。
fakearray#gen
fakearray#gen(num, first, second)
はfakearray#val
をnum
回呼び出して、結果をg:fakearray#separator
区切りで結合します。
b:fakearray_separator
も使えます。
(fakearray)
プロンプトに入力する値の個数によって動作が変わります。
入力数 | 動作 |
---|---|
1 | fakearray#gen({input num}, g:fakearray#prompt_first , g:fakearray#prompt_second ) |
2 | fakearray#gen({input1 num}, {input2 str}, '' ) |
3 | fakearray#gen({input1}, {input2}, {input3}) |
入力数1と3は見たまんまです。
2のときはfakearray#gen
の第3引数を''
にしているのでfake#gen
が呼ばれます。
内部で入力値にevalをかけているので文字列を入力するときはクオートを省略してはいけません。
キーマップ
インサートモードのキーマップは悩みますよね。
Emacsバインドにしている人は特に。
プラグインのデフォルトでは<F3>
に割り当てていますが、私は<c-/>a
に割り当てています。
ただし、<c-/>
をテキストとして入力しても動作しないので、代わりに<c-v><c-/>
で特殊文字を入力する必要があります。
最後に
Vimには乱数を生成する関数がないので、このプラグインではvim-fakeを使いました。
乱数を生成する方法は他にもあります。
初めてvim-themisでテストを書きました。
なかなか面白かったです。
quickrun.vimからPrevimを呼んでMarkdownをプレビューする
PrevimはMarkdownプレビュー用のVimプラグインです。
スタンドアロンで動作するのが魅力です。
そんなPrevimをQuickRunで呼び出せたらキーマップの節約になります。
autocmdでMarkdownのときだけキーマップを上書きしてもいいのですが、どうせならスマートに解決。
let g:quickrun_config = { \ 'markdown': { \ 'runner': 'shell', \ 'outputter': 'null', \ 'command': ':PrevimOpen', \ 'exec': '%c', \ }, \ }
ざっと見た感じrunner
にshell
を指定して、command
を:
で始めればVimのコマンドが呼べるようです。
空行をレジスタに送らないVimオペレータ作ってみた
dd
で空行を削除したらヤンクしたテキストが上書きされてしまった… なんてことありますよね。
"_dd
でブラックホールに送れば済む話ですが、空行を消すために毎回レジスタ指定するのは面倒くさい。
そんな思いから、空行(空白のみも含む)を削除したときは自動でブラックホールに送ってくれるオペレータ作ってみました。
nmap d <Plug>(operator-blank2void) xmap d <Plug>(operator-blank2void) nmap <silent>dd :exec "normal Vd"<cr> call operator#user#define('blank2void', 'Operator_blank2void') function! Operator_blank2void(motion_wise) abort let v = operator#user#visual_command_from_wise_name(a:motion_wise) if join(getline("'[", "']"), '') =~ '\%^\_s*\%$' execute printf('normal! `[%s`]"_d', v) else execute printf('normal! `[%s`]d', v) endif endfunction
dd
のキーマップが冗長に思えますが、これは選択時のチラツキを無くすためです。
switch系プラグイン vim-clurinを強化した話
switch系プラグインについて
switch系プラグインとは定義されたルールに従ってテキストを置換する類のプラグインです。
よくあるルールはTrue
とFalse
を切り替える、if
-> else if
-> else
の順で切り替えるなどです。
vim-clurinの基本的な使い方は作者であるsynganさんの記事を参照してください。 qiita.com
switch.vimとの違い
変更内容の前に、筆者がvim-clurinを使ってる理由をざっと説明します。
筆者はvim-clurinの前はswitch.vimを使っていました。
筆者が使っていた範囲でのswitch.vimとの大きな違いは以下の2つです。
- ファイルタイプ毎の設定をグローバル変数1つで定義できる。
- switch.vimはファイルタイプ毎の設定をautocmdを使ってバッファローカル変数に定義する必要がありました。
- パターンにマッチしたら関数を呼べる。
- ぱっと見設定が冗長に感じる
- 拡張性のために冗長な書き方ができますが、ある程度簡略化して書けます。
関数を呼べるのがなかなか強力です。
改善内容
各変更のサンプルはリポジトリのREADMEを見てください。
※ GitHubを見る限りsynganさんは現在あまり活動されてないようなので、試す場合は筆者のリポジトリを使ってください。
1. ファイルタイプ別設定のキーに複数言語を指定できる
g:clurin
のキーには'c'
の用に単一のファイルタイプしか指定できませんでしたが、スペース区切りで複数の言語を指定できるようにしました。
C言語とC++共用の設定であればキーは'c cpp'
です。もちろん、C言語、C++独自の設定と共存できます。
2. デフォルトの設定をファイルタイプ毎に無効に出来る
g:clurin
で'use_default': 0
を指定すれば、デフォルトの設定を全て無効化出来ましたが、ファイルタイプ毎に無効化は出来ませんでした。
各ファイルタイプの設定で、'use_default': 0
を指定すれば無効化できるようになりました。
3. 関数内で置換処理を終了できる。
'replace'
で関数を指定した場合、'pattern'
にマッチしたテキストの置換には指定した関数の戻り値が使用されます。
ただ、複雑な置換をする場合は関数内で置換処理を行って、戻り値は使用しないほうが都合が良いときがあります。
そんな場合は'quit': 1
を指定すれば、関数呼び出し後に置換処理を即終了出来ます。
4. 'replace'
で'\2'
以降も使えるようにした。
'replace'
で使える部分正規表現が'\1'
だけだったので'\2'
以降も使えるようにしました。
ただし、これは破壊的な変更です。
'replace'
に指定した関数の第1引数が変わります。
- before:
'\1'
の文字列 - after:
'\1'
から'\9'
までのリスト
最後に
これらの変更でRubyのdo ~ end
と{ ~ }
の切り替えなど、様々な事が出来るようになりました。
やはり、関数を呼べるのは強力ですね。
vim-clurinはソースが読みやすかったので変更が用意でした。
見習いたいです。
btrfsで空き領域が開放されずにのディスク使用率が100%になる。
1週間ほど前、btrfsのデバイスが容量が空いているのにも関わらず使用率が100%のまま変わらない事があった。
いろいろやった気がするが、ほとんど思い出せないので覚えてる限りの解決法を載せておく。
注意点
btrfsは空き領域をプールするのでdf
コマンドで見れる情報が正しいとは限らない。
ルートディレクトリの情報を見る場合は下記のコマンド。
filesystem
は短縮してf
でもいい
btrfs filesystem df -h /
解決策
btrfsのsubvolumeを削除したら領域が開放された。
「領域が開放されないときはsubvolumeを削除しろ」と言うサイトは幾つかあったが、subvolumeなんて機能は使った覚えがなかったので無視していた。
しかし、自分で直接使った記憶はなくてもDockerが使っていた。
Dockerが領域を開放しなかったわけではないだろうが、subvolumeを全部消したら解決。
消えて困るコンテナはなかったので楽だった。
削除方法は覚えてないのでBtrfs - ArchWikiでも見てください。
letを使ってシェルで条件演算子(三項演算子)
ポイント
- シェル変数は$を省略する
- 未定義の変数は0として扱われる
- 文字列は扱えない
- シェルと反対にtrueは1、falseが0
$ let 'a = 1? 11 : 22' $ echo $a 11 $ let 'a = 0? 11 : 22' $ echo $a 22 $ let 'a = 3==3? 11: 22' $ echo $a 11
条件演算子以外にもインクリメントや復号代入も可能です。
$ let 'b++' $ echo $b 1 $ let 'c += 3' $ echo $c 3
ちなみに$((expr))
でも同様の事が可能。
$ echo $((d -= 10)) echo -10 $ echo $d -10
Have a nice shell life!