🏎️
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