🔛

Vimでインデント幅の単位で左右移動する

2023/09/20に公開

この記事はVim駅伝の2023-09-20の記事です。
前回の記事はFohteさんのGhostText: Vim でブラウザのテキストエリアを入力するです。
次回の記事はstaticWagomUさんの闇の力への入門 ddc.vim編です。


Vimの左右移動の改善マッピングを紹介します。
インデントの内部で、インデント幅の単位で左右移動できるようになります。

※2024/03/29追記 quantized_lで無限ループにならないようlastcolの条件を追加

" カーソルがインデント内部ならtrue
function! s:in_indent() abort
  return col('.') <= indent('.')
endfunction

" カーソルがインデントとずれた位置ならtrue
function! s:not_fit_indent() abort
  return !!((col('.') - 1) % shiftwidth())
endfunction

function! s:quantized_h(cnt = 1) abort
  if a:cnt > 1 || !&expandtab
    execute printf('normal! %sh', a:cnt)
    return
  endif
  normal! h
  while s:in_indent() && s:not_fit_indent()
    normal! h
  endwhile
endfunction

function! s:quantized_l(cnt = 1) abort
  if a:cnt > 1 || !&expandtab
    execute printf('normal! %sl', a:cnt)
    return
  endif
  normal! l
  let lastcol = col('$') - 1
  while s:in_indent() && s:not_fit_indent()
        \ && col('.') != lastcol
    normal! l
  endwhile
endfunction

noremap h <cmd>call <sid>quantized_h(v:count1)<cr>
noremap l <cmd>call <sid>quantized_l(v:count1)<cr>

このマッピングは、h lを普通に使った場合およびカウントをつけて使った場合(3hなど)は通常の左右移動となります。また、タブ文字によるインデント(expandtabが0)の場合でも通常の挙動と同じです。

効果を発揮するのは、以下のように、スペースでインデントされた構文の内部にカーソルがあるときです。このとき、インデント幅(shiftwidthで算出)に揃うようにカーソルが移動します。具体的には、whilenormal!を使って、インデントに揃うまでh lを連打しています。

if a > 1
  if b > 2
    if c > 3
  |  hogehoge
  ^ ここにカーソル
    endif
  endif
endif


インデント内部ではh/lで2字移動する

行頭への移動には^/0で移動するのが高速ですが、インデント内部でささっと移動できるとたまに便利です。
普段の移動も邪魔しないので、興味があればお試しください。

Discussion