🌴

pythonのコードブロックの始点終点に移動するVimプラグインを作った

2021/12/13に公開

はじめに

画面に収まらない長大なコードブロックを持ったりif文やfor文で多重にネストされてインデントが深くなったりするpythonコード[1]では現在のインデントに注意を払う労力が増えると思います。
内部の処理を関数で切り出すなどしてその労力を軽減するアプローチもあるかと思いますがコードを読む際などそれが実現出来ない場合もあると思います。
VimではC言語の{}などに対して対になる括弧に移動するコマンド%が提供されていますが、このようなコマンドがpythonのコードでも使えれば役立つのではと思い、現在のコードブロックの始点や終点に移動するVimプラグインを作りました。 本記事ではそのVim プラグインの使い方、処理を紹介します。

リポジトリはこちらです。
https://github.com/kawagh/jumpblock.vim

使い方

インストール

vim-plugを使っていれば.vimrcに以下の行を加えてPlugInstallすればコマンドが使えるようになります。

Plug 'kawagh/jumpblock.vim'

コマンド

:JumpBlock
:RjumpBlock

:JumpBlockでコードブロック終点に移動、:RjumpBlockで始点に移動します。

処理

始点の捉え方

  • pythonのコードブロックを形成する合図は文末のコロン(:)なのでここを始点に捉えます({}での{に相当)。

終点の捉え方

  • インデントが同一以下になる行が見つかるまで下の行を見るループをします。インデントが同一以下の行が見つかったらそこではコードブロックが終了しているとみなせるのでその前の行にジャンプします。
    • この時に空行の存在に注意が必要です。終端ではないがインデントが同一以下になる行なので終端と認識されてしまうので空行をスキップしてループをすると良いです(Vim Scriptではnextnonblank()など次の非空行の番号を返す関数が提供されていて便利でした)。

実装

function! s:jump_block_f()
    let cline = getline(".")
    let lastchar = cline[strlen(cline)-1]
    if lastchar == ":"
        let lnum = line(".")
        let start_indent = indent(line("."))
        while indent((lnum+1)->nextnonblank()) > start_indent
            let lnum = (lnum+1)->nextnonblank()
        endwhile
        :call cursor((lnum)->prevnonblank(),1000)
    endif
endfunction

function! s:rev_jump_block_f()
    if indent(".") != 0
        let cline = getline(".")
        let lastchar = cline[strlen(cline)-1]
        let lnum = line(".")
        let start_indent = indent(line("."))
        while indent((lnum-1)->prevnonblank()) >= start_indent
            let lnum = (lnum-1)->prevnonblank()
        endwhile
        :call cursor((lnum-1)->prevnonblank(),1000)
    endif
endfunction
脚注
  1. 個人的にindent jungleと呼んでいます ↩︎

Discussion