🧮
Vim/NeovimでgOでMarkdownのTOCを抽出する
Neovimで、gO
というキーマッピングをご存知でしょうか。
VimにはないNeovimのマッピングで、ファイルのアウトラインを抽出します(gOはおそらくgo Outlineのイメージ)。
この機能は、現時点ではhelpとmanファイルにしか対応していません。
これをMarkdownでも行う設定を紹介します。
Markdown TOC抽出関数
以下を設定することで、Markdownファイル内のヘッダを抽出し、Quickfixリストに一覧します。
Markdown限定の処理なので、ftpluginに入れると良いと思います。
after/ftplugin/markdown.vim
function! s:markdown_outline() abort
let fname = @%
let current_win_id = win_getid()
" # heading
execute 'vimgrep /^#\{1,6} .*$/j' fname
" heading
" ===
execute 'vimgrepadd /\zs\S\+\ze\n[=-]\+$/j' fname
let qflist = getqflist()
if len(qflist) == 0
cclose
return
endif
" make sure to focus original window because synID works only in current window
call win_gotoid(current_win_id)
call filter(qflist,
\ 'synIDattr(synID(v:val.lnum, v:val.col, 1), "name") != "markdownCodeBlock"'
\ )
call sort(qflist, {a,b -> a.lnum - b.lnum})
call setqflist(qflist)
call setqflist([], 'r', {'title': fname .. ' TOC'})
copen
endfunction
nnoremap <buffer> gO <Cmd>call <sid>markdown_outline()<CR>
この記事のmdファイルで使用した例
解説
最初のvimgrep
は以下の形式のヘッダを抽出します。
# h1
## h2
### h3
#### h4
##### h5
###### h6
その後のvimgrepadd
は以下の形式のヘッダを抽出します。
h1
====
h2
---
上記が混在した場合にファイル内の順序を揃えるため、lnum
を用いてソートしています。
なお、code block内の要素はsyntax情報を利用して除去しています。
バリエーション
こちらで紹介したものは筆者の好みでQuickfixリストを使っていますが、本来のgO
はロケーションリストが使用されます。
基本構造は変わらないので、getqflist
をgetloclist
に変更するなどの修正を加えれば、ロケーションリストを使うこともできます。お好みで修正してください。
Discussion