🐯
Vimでアウトライン範囲を選択するtextobject
以下のような「現在の行と、その次以降の行で現在行よりインデントの深い範囲」を選択するtextobjectを作りました。
foldと組み合わせるとアウトライナー的に使用できます。
箇条書きの入れ子構造を意識して作ったのですが、類似した構造で記述される言語(pythonやlispなど)を開発する際にも便利かもしれません。
TextobjectOutline
以下のコードをvimrcなどで実行してください。
関数内のfrom
とto
が選択範囲の行番号を表しています。
function! s:textobject_outline(...) abort
let from_parent = index(a:000, 'from_parent') >= 0
let with_blank = index(a:000, 'with_blank') >= 0
" get current line and indent
let from = line('.')
let indent = indent(from)
if indent < 0
return
endif
let to = from
" search first parent
if from_parent && from > 1 && indent > 0
let lnum = from - 1
while indent <= indent(lnum) || (with_blank && getline(lnum) =~ '^\s*$')
let lnum -= 1
endwhile
" update current line and indent
let from = lnum
call cursor(from, 0)
let indent = indent(from)
endif
" search last child
let lnum = to + 1
while indent < indent(lnum) || (with_blank && getline(lnum) =~ '^\s*$')
let to = lnum
let lnum += 1
endwhile
" exit visual mode
let m = mode()
if m ==# 'v' || m ==# 'V' || m == "\<C-v>"
execute 'normal! ' .. m
endif
" select with line-visual mode
normal! V
call cursor(to, 0)
normal! o
endfunction
command! -nargs=* TextobjectOutline call s:textobject_outline(<f-args>)
xnoremap io <Cmd>TextobjectOutline<CR>
xnoremap ao <Cmd>TextobjectOutline from_parent<CR>
xnoremap iO <Cmd>TextobjectOutline with_blank<CR>
xnoremap aO <Cmd>TextobjectOutline from_parent with_blank<CR>
onoremap io <Cmd>TextobjectOutline<CR>
onoremap ao <Cmd>TextobjectOutline from_parent<CR>
onoremap iO <Cmd>TextobjectOutline with_blank<CR>
onoremap aO <Cmd>TextobjectOutline from_parent with_blank<CR>
ここでは基本動作をio
(in outline)にマップしていますが、マッピングはお好みで調整してください。
普通に:TextobjectOutline
を実行して選択することもできます。
動作説明
TextobjectOutline
は2種の文字列引数をとり、それらの有無によって2×2=4通りの動作をします。
- 通常
- 現在の行を選択
- 下の行が現在の行よりインデントが深ければ順次選択
- 空白行はインデントが0と判定されるので選択しない
- 引数
with_blank
をつける- 空白行も含める
- 引数
with_parent
をつける- 現在行より上で、現在よりインデントが浅い行(親)を起点とする
- 現在のインデントが0の場合は無効
参考
vim-textobj-indentが類似の機能を提供していますが、微妙に違いました。
visual modeを脱出する処理などはmini.nvimのindentscopeモジュールを参考にしました。
markdownで箇条書きを書きやすくする設定に関してはこちら。
Discussion