はじめに
これまで、switch.vimを使っていると、順方向にしかいけないことと, ctrl-A
を +
に割り振りたいことなどに不満がでてきたので、clurin.vim
を作ってみた。
- clurin.vim: https://github.com/syngan/vim-clurin
提供する機能により、Sun
→ Mon
→ Tue
→ ... のような切り替えができます。本プラグインの特徴は以下の通りです
- 正規表現での指定が可能 (
switch.vim
相当の機能はだいたいできる.) - 順方向だけでなく逆方向にもたどれる (
cycle.vim
相当のことができる) - n 個先にも飛べる
- カーソル直下の文字にマッチするものがなかった場合の処理を設定可能
- ファイルタイプ毎の設定が容易. (好みの問題かも)
switch.vim
からの現時点での機能落ちは以下だと思います. 他にもあったらごめんなさい。
- separate mappings (あまり必要性が...)
- nested dict definitions (実現できないわけではない)
使い方
.vimrc
に以下のように書いてください。
nmap +<Plug>(clurin-next)
nmap -<Plug>(clurin-prev)
vmap +<Plug>(clurin-next)
vmap -<Plug>(clurin-prev)
あとは、
1. Sun
という文字列の上にカーソルを置いて,
2. +
を押すと, Mon
になり,
3. 2+
を押すと, Wed
になり,
4. -
を押すと, Tue
になります.
カスタマイズ
設定はグローバル変数 g:clurin
の定義により行います。g:clurin
は filetype
をキーとする辞書です。 switch.vim
では「次にいくにはどう変換するか」を定義しますが、clurin.vim
では「自分になるにはどう変換するか」を定義します。以下に例を示します。
function!g:CountUp(str, cnt,def) abort
" a:str: マッチした文字列 " a:cnt: clurin-next なら正の値, clurin-prev なら負の値 " a:def: マッチした定義return str2nr(a:str)+a:cnt
endfunctionfunction!g:CtrlAX(cnt) abort
ifa:cnt >=0
execute 'normal!'a:cnt . "\<C-A>"else
execute 'normal!'(-a:cnt) . "\<C-X>"endifendfunctionletg:clurin = {
\ '-': {
\ 'def': [
\ ['on','off'],
\ [
\ {'pattern': '\<true\>','replace': 'true'},
\ {'pattern': '\<false\>','replace': 'false'}
\ ],
\ ]
\ },
\ 'c': {
\ 'def': [
\ ['&&','||'],
\ [
\ {'pattern': '\(\k\+\)\.','replace': '\1.'},
\ {'pattern': '\(\k\+\)->','replace': '\1->'}
\ ]
\ ],
\ 'nomatch': function('g:CtrlAX')
\ },
\ 'vim': {
\ 'def': [
\ [
\ {'pattern': '''\(\k\+\)''','replace': '''\1'''},
\ {'pattern': '"\(\k\+\)"','replace': '"\1"'}
\ ],
\ [
\ {'pattern': '\(-\?\d\+\)','replace': function('g:CountUp')}
\ ]
\ ]
\ }
\}
詳細をみていくと、
let g:clurin = {
\ '-': {
-
はデフォルトの設定を表します。通常すべてのファイルタイプで使用されます。c
は ft=c
の場合専用の設定になります。
\ 'def': [
\ ['on', 'off'],
def
の値はリストで、そこに切り替えるグループを定義します。この場合、on
と off
を切り替える定義になっています。
\ [
\ {'pattern': '\<true\>', 'replace': 'true'},
\ {'pattern': '\<false\>', 'replace': 'false'}
\ ],
....
\ [
\ {'pattern': '\(\k\+\)\.', 'replace': '\1.'},
\ {'pattern': '\(\k\+\)->', 'replace': '\1->'}
\ ]
正規表現を使いたい場合には、文字列ではなく辞書を使用します。pattern
にマッチしたもの, replace
に自分に変換するときのルールを書きます. 上のグループは true
と false
のグループを表しています.
\ 'nomatch': function('g:CtrlAX')
マッチするものがなかった場合の処理を Funcref で渡すことができます. この設定の場合, g:CtrlAX
を呼び出して、Ctrl-A
, Ctrl-X
相当を実現しています。
\ [
\ {'pattern': '\(-\?\d\+\)', 'replace': function('g:CountUp')}
\ ]
(だいぶルール違反な気もしていますが)変換ルールに Funcref を渡すことも可能です。
うまく定義してやれば, vim-speeddatingと共存みたいなこともできると思いますし, switch.vim
の Nested dict definitions
も実現できるはずです。
その他、サイクリックにしないとか、デフォルトの設定を利用しないとかも指定できます。詳細は近いうち更新されるであろうヘルプを参照してください。
マッチ判定ルール
カーソル下の文字列が複数のパターンにマッチする場合には以下の優先順位によりどのパターンを利用するかを判定します.
1. 開始位置がカーソル位置に近いほう
2. 対象文字列が短いほう
3. 定義された位置がはやいほう
どちらの場合もマッチしなかったほうがカーソル位置を移動すればマッチ対象にできるので、このルールを使用するようにしました。
定義は以下の順序で探索します.
1. g:clurin[&filetype]
2. g:clurin['-']
3. clurin.vim
デフォルトの &filetype
用定義
4. clurin.vim
デフォルト定義 (-
)
おわりに
何か問題・リクエスト等あれば issuesによろしくお願いします.