🏎️
VimでTextObjの末尾や先頭に移動する
何ができるようになるか?
ノーマルモードにてg
+ テキストオブジェクトで
テキストオブジェクトの先頭や末尾に移動できるようになります!
例えばテキストオブジェクトt
はHTMLタグなので、
█
がカーソル位置としてgIt
で以下の様に移動できるようになります
これが
<div>
foo
bar
...
baz█
</div>
↓こう
<div>
█oo
bar
...
baz
</div>
%
と違い任意のテキストオブジェクトを指定できるので便利!
…たぶん便利!
実装
こんな感じでいけます
-
テキストオブジェクトの末尾に移動
function! s:ToTail(_) call getpos("']")->setpos('.') endfunction noremap <SID>(ToTail) <ScriptCmd>set operatorfunc=<SID>ToTail<CR>g@ nmap ga <SID>(ToTail)a nmap gi <SID>(ToTail)i
-
テキストオブジェクトの先頭に移動
function! s:ToHead(_) let p = getpos("'[") call setpos('.', p) if p[2] <= 1 normal ^ elseif getline(p[1])->len() <= p[2] normal j^ endif endfunction noremap <SID>(ToHead) <ScriptCmd>set operatorfunc=<SID>ToHead<CR>g@ nmap gA <SID>(ToHead)a nmap gI <SID>(ToHead)i
解説
ga
、gi
でテキストオブジェクトの末尾、gA
、gI
で先頭に移動します
実装について
s:ToTail()
テキストオブジェクトの末尾にカーソルをセットしています
これだけで書けちゃうんですね
s:ToHead()
先頭への移動はちょっと微調整しています
- インデントを無視したい場面が多かったので
normal ^
で位置調整してます - 同様に
gI
での移動で行末に移動した場合も次の行の先頭へ位置調整してます
マッピングについて
テキストオブジェクトを扱うときはoperatorfunc
を使いますが、単純に
noremap g <ScriptCmd>set operatorfunc=<SID>ToHead<CR>g@
としてしまうと、g
で始まるマッピングが軒並使えなくなってしまいます!
なので、スクリプトローカルな<SID>(ToTail)
と<SID>(ToHead)
を定義し回避しています
デフォルトのマッピングについて
-
ga
は使う頻度は少ないと思いますが、残したいなら<Leader>ga
とかに退避させましょう -
gi
はg;i
で代用できます
他の案
]a
、]i
、[a
、[i
にマッピングするのもありかと思います(自分は普段使いの40%キーボードとスマホで打ちづらいのでやりませんが)
Ga
、Gi
、ga
、gi
にマッピングしてG
はGG
に退避するのもありかもしれませんね🤔
G
を他のマッピングのprefixにも使えそうですし、gg
に対してのGG
も直感的な気がします
ビジュアルモードとオペレーターに対応したプラグイン化
このままだとノーマルモードでしか動かないので、
ビジュアルモードとオペレーターに対応してプラグイン化してみました
こんな感じで動くようになると思います
call dein#add('utubo/vim-headtail')
HeadTailMap g G
追伸
今日12/20は私の誕生日です!わーい!🎂ฅ⊏'ꣲ'|ฅ
Discussion