🤲
Vimの<CMD>マップでrangeを使う
以下のEchoLines
コマンドおよびマッピングがあるとします。
range
を受け付け、ノーマルモードでは現在のカーソル位置の行番号が、ビジュアルモードでは現在の選択範囲の行番号が、それぞれ表示されることを期待しています。
function! s:echo_lines(from, to) abort
let from = a:from
let to = a:to
let lnum = from
while lnum <= to
echo 'L' .. lnum
let lnum += 1
endwhile
endfunction
command! -range EchoLines call s:echo_lines(<line1>, <line2>)
nnoremap <C-l> <Cmd>EchoLines<CR>
xnoremap <C-l> <Cmd>EchoLines<CR>
コマンドとマッピングの動作は以下のようになります。
- ノーマルモードで
:EchoLines
を実行 → 現在の行番号が表示される ✅ - ノーマルモードで
<C-l>
を実行 → 現在の行番号が表示される ✅ - ビジュアルモードで選択し、
:'<,'>EchoLines
を実行 → 選択範囲の行番号が表示される ✅ - ビジュアルモードで選択し、
<C-l>
を実行 → 現在の行番号が表示される ❌
<Cmd>
マッピングでは範囲を渡せないので、<C-l>
押下時に期待した動作をしません。
実行される関数内部でline('v')
を使用することで、これを解決できます。
function! s:echo_lines(from, to) abort
let from = a:from
let to = a:to
" 追加
let another = line('v')
if from == to && from != another
if another < from
let from = another
else
let to = another
endif
endif
" 追加
let lnum = from
while lnum <= to
echo 'L' .. lnum
let lnum += 1
endwhile
endfunction
command! -range EchoLines call s:echo_lines(<line1>, <line2>)
nnoremap <C-l> <Cmd>EchoLines<CR>
xnoremap <C-l> <Cmd>EchoLines<CR>
line('v')
を使って「選択領域の反対側のカーソル位置」を取得できるので、現在の選択範囲を算出できます。
from == to && from != another
の条件を入れているので、ノーマルモードで実行した場合や、明示的にrangeが指定された場合には影響しません。
Discussion