asyncomplete を filetype で toggle できるようにする

ぺりー
6 min readNov 4, 2024

--

本記事は Vim駅伝 2024–11–04 に寄稿しました。

こんにちは!ぺりーです。

本日は prabirshrestha/asyncomplete.vim を filetype で toggle して使えるようにしたぷち設定を紹介します。

prabirshrestha/asyncomplete.vim は timers を使って実装された非同期の自動補完を可能にする plugin です。

作者は VimConf 2019 にも登壇された Prabir Shrestha 氏で、vim-lsp の作者としても有名です。

LSPと掛け合わせることでさらにスムーズに入力することができます。

強力でファンの多い plugin ではありますが、私の場合は書き慣れた言語を書くことが多く、その際に自動補完をほとんど使わないため、補完が非同期である必要がなく、今までインストールしていませんでした。

しかし、新しく言語を勉強したり書き慣れない言語を書いていたりするときや Vim も VSCode と同じことできる!を証明するときなど、非同期で自動補完が出てくると助かるかもと思うようになり、今回 filetype で toggle できるようにしました。

もともと plugin が必要になるまでは有効化したくないと思っており、今回もデフォルトは無効で、必要になった時にだけ有効にできるようにしました。

filetype で toggle できるようにしたのは先に述べたように書き慣れていない言語や特定のユースケースのみで有効にしたいと思ったからです。

柔軟に toggle できるようにするために filetype のホワイトリストを記すような管理ではなく関数で toggle できるようにしました。

asyncomplete を toggle して有効にした場合に、カレントバッファの filetype と一致するバッファでは asyncomplete が有効になるようにします。

:ls
1 %a "main.go" line 4
2 #a "main2.go" line 0
3 "main3.go" line 0
4 a "main.c" line 0

例えば、カレントバッファ( main.go )で toggle して有効化した場合、 main2.go , main3.go などバッファリスト内の Go ファイルはもちろん、新規に開く Go ファイルでも asyncomplete が有効化されるようになります。
一方、バッファリスト内外を問わず Go ファイル以外(例えば main.c )は asyncomplete が無効のままになります。

# disable for all buffers by default
g:asyncomplete_enable_for_all = 0
g:asyncomplete_enabled_filetype = {}

# Toggle asyncomplete for the current filetype.
# Handle exceptions raised by lazy loading of plugins.
def! g:ToggleAsyncompleteForFiletype() #{{{
const enabled = get(g:asyncomplete_enabled_filetype, &ft, 0)
if enabled
remove(g:asyncomplete_enabled_filetype, &ft)
try
call g:asyncomplete#disable_for_buffer()
catch /E117/
endtry
return
endif
try
call g:asyncomplete#enable_for_buffer()
catch /E117/
echomsg 'asyncomplete not loaded yet.'
return
endtry
# If the plugin is not loaded, it is conceivable that this will be called
# again without being applied to the current buffer at least, so set the
# flag only when successful.
g:asyncomplete_enabled_filetype[&ft] = 1
enddef #}}}

# Apply asyncomplete settings to the current buffer if the filetype is
# enabled.
# Handle exceptions raised by lazy loading of plugins.
def! g:ApplyAsyncompleteSettingByFileType() #{{{
const enabled = get(g:asyncomplete_enabled_filetype, &ft, 0)
if enabled
try
call g:asyncomplete#enable_for_buffer()
catch /E117/
endtry
return
endif
try
call g:asyncomplete#disable_for_buffer()
catch /E117/
endtry
enddef #}}}

# Use BufEnter to apply settings when switching between buffers, as FileType
# is triggered only when the filetype changes or when a file is first opened.
# Buffer ensures that the asyncomplete settings are applied even when the
# filetype remains the same.
augroup AsyncompleteFiletypeToggle
autocmd!
autocmd BufEnter * call g:ApplyAsyncompleteSettingByFileType()
augroup END

辞書に filetype ごとの設定を保持し BufEnter event で有効化された filetype の場合には g:asyncomplete#enable_for_buffer() を実行し、設定が適用されていない場合には有効になるように実装しました。

BufRead ではバッファロードされている場合に toggle できないため、BufEnter を使用しています。

plugin の読み込みには自作 plugin manager を使用して遅延読み込みを実装しているため、起動後にすぐに toggle した場合は E117 が発生する可能性があるため、例外を捕捉するようにしてあります。

--

--

ぺりー
ぺりー

Written by ぺりー

Satoru Kitaguchi. Backend Engineer at eureka, Inc.

No responses yet