ハイパーマッスルエンジニア

Vim、ShellScriptについてよく書く

【Neovim】好きな位置にテキストを埋め込んだりハイライトできる「ExtMark」の使い方

f:id:rasukarusan:20210822204151p:plain
 

ExtMarkとは

指定した行、列にマーカーをセットできる。セットしたマーカー(位置)に好きな文字列を表示したり、ハイライトできたりする。
テキストの変更を追跡して表示できるので、インデント幅の表示やスペルミスを表すために使われたりする。
ヘルプは:h api-extended-marksで引けます。

実際どのようなものなのか

見たほうが早いのでExtMarkでできることの一例を載せる。

好きな位置をハイライト

好きな位置に文字列を挿入、テキストの変更も追跡する

使い方

ExtMarkの作成

test.vimを作成し、下記を記載してsource %してみましょう。

let g:mark_ns = nvim_create_namespace('myplugin')
let g:mark_id = nvim_buf_set_extmark(0, g:mark_ns, 0, 5, {"end_col" : 10, "hl_group" : "Visual"})

1行目の5文字目から10文字目がハイライトされます。

f:id:rasukarusan:20210822202936p:plain:w500
文字列をハイライト

ハイライトの他に、文字を表示させることもできます。VirtualTextというものですね。

let g:mark_ns = nvim_create_namespace('myplugin')
let g:mark_id = nvim_buf_set_extmark(0, g:mark_ns, 0, 5, {
      \ "virt_text":[
          \ ['Hello', 'ErrorMsg'],
          \ ['World!', 'Visual']
        \ ],
      \ "virt_text_pos" : 'overlay',
      \})

"virt_text_pos" : 'overlay''overlay'ではなく'eol'にすると、行末にテキストを表示させることができます。

作成したExMarksの一覧を取得

call nvim_buf_get_extmarks(0, g:mark_ns, 0, -1, {})

結果は下記のような配列で返ってきます。

[
  [1, 0, 5], " [マークID, 行, 列]
  [2, 1, 5],
  [3, 4, 10],
]

マーカーの詳細を取得したい場合はオプションに"details": 1を追加します。

echo nvim_buf_get_extmarks(0, g:mark_ns, 0, -1, {"details": 1})
" [
"    [1, 0, 5, {'hl_group': 'Visual', 'priority': 4096, 'end_col': 10, 'end_row': 0}],
"    [2, 0, 5, {'hl_group': 'Visual', 'priority': 4096, 'end_col': 10, 'end_row': 0}], 
" ]

また、特定のマーカーを取得したい場合はnvim_buf_get_extmark_by_idで取得できます。

call nvim_buf_get_extmark_by_id(0, g:mark_ns, g:mark_id, {})

ExtMarkの削除

削除するときは作成時に返ってくるmark_idを利用します。

call nvim_buf_del_extmark(0, g:mark_ns, g:mark_id)

現在バッファのExtMarkすべてを削除する場合は、一覧取得のnvim_buf_get_extmarksを利用します。

" 現在バッファのExtMarkすべて削除
let extmarks = nvim_buf_get_extmarks(0, g:mark_ns, 0, -1, {})
for extmark in extmarks
    let mark_id = extmark[0]
    call nvim_buf_del_extmark(0, g:mark_ns, mark_id)
endfor

ExtMarkの使いみち

ドキュメントに書いてあるとおり、インデント幅の表示やlinterプラグインなどと相性が良さそうです。
いくつかExtMarkを使ったプラグインを紹介しておきます。

nvim-select-multi-line

github.com

好きな行を選択し、yankやdeleteができるプラグイン。選択した行のハイライトにExtMarkを利用している。

gesture.nvim

github.com

マウスジェスチャーで指定したアクションを実行できるプラグイン。マウスの軌跡を表示するのにExtMarkを利用。めちゃくちゃおもしろい。 解説記事もあります。

zenn.dev

nvim-dap

github.com

デバッグアダプター。描画目的ではなく、シンプルにセットしたマーカーから行・列を取得し、ごにょごにょするという使い方をされている。

おわりに

Floating Windowに続く描画の新たな可能性が広がるAPIで、アイデア次第で色々できそうなのがいい!
しばらくExtMarkでできることを模索していきたい。 あと、テキストの追跡をどうやっているのかは下記の記事がわかりやすくて面白かったのでぜひ読んでおきたい。

blog.atom.io