LoginSignup
3
2

More than 3 years have passed since last update.

neovimでjedi-language-serverをnvim-lspのデフォルト以外の設定で使う

Last updated at Posted at 2020-07-24

まえがき

最近vimからneovimに移行するにあたってPythonの開発環境を整えているのですが,jedi-language-serverの設定に関する情報が少なかったので,備忘録がてらまとめます.

LSPを使うのが初めてということもあり,「とりあえずは補完が出てくれればいいや,リンターやフォーマッタなどはあとからにしよう」という感じで今回は補完オンリーをターゲットにして環境を開発構築していきます.

環境

今回セットアップした環境は以下の通りです.

  • OS: macOS 10.14 (Mojave)
  • neovim: 0.5.0 (HomebrewのHEAD 1ca67a7)
  • Python: 3.8.5 (Homebrewでインストールしたやつ)
  • LSPクライアント: neovim0.5.0から標準のクライアント + nvim-lsp
  • LSPサーバ: jedi-language-server
  • 補完: deoplete.nvim

巷ではpython-language-serverを使用している例が多いのですが,私の環境では補完候補が出てくるのがものすごく遅かったのでjedi-language-serverを採用しています.

Luaの設定

jedi-language-serverをnvim-lspのデフォルト設定で使うのは簡単です.以下の設定を init.vim に入れておけば使えるようにはなります.

lua <<END
local nvim_lsp = require 'nvim_lsp'

nvim_lsp.jedi_language_server.setup{}
END

が,デフォルトだとリンターの反応が早い & 張り切りすぎてうるさい.タイプ途中に構文エラーで怒られても...という感じなので,リンターをオフにします.

lua << END
local nvim_lsp = require 'nvim_lsp'

nvim_lsp.jedi_language_server.setup{
  init_options = {
    diagnostics = {
      enable = false,
    },
    completion = {
      disableSnippets = true,
    },
    jediSettings = {
      autoImportModules = {'numpy', 'pandas'},
    },
  },
}
END

設定可能な項目は,GitHubのREADMEを参照ください.

pylsの場合はsettings.pyls.pluginsなんかに記載するのですが,jedi-language-serverはinit_optionsのようです.このへんの設定のお作法?がよく分かっていないのがつらいところ.

補完をした際にtextEditのエラーが発生する

上記の設定を行い,構文エラーで怒られないことを確認した後,意気揚々とnp.と打ったところ,以下のエラーが発生しました.

Error executing vim.schedule lua callback: ...vim/HEAD-1ca67a7/share/nvim/runtime/lua/vim/lsp/util.lua:277: attempt to index field 'textEdit' (a userdata value)

どうやらLuaのnilvim.NILの違いが原因のエラーのようです.既にバグは報告されており,近いうちに修正されるとは思うのですが,今のところは以下の変更を加えることで使えるようになります.

diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 52a6fe89f..fc619c8a8 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -274,13 +274,13 @@ end
 -- textEdit.newText > insertText > label
 -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
 local function get_completion_word(item)
-  if item.textEdit ~= nil and item.textEdit.newText ~= nil then
+  if item.textEdit ~= vim.NIL and item.textEdit.newText ~= vim.NIL then
     if protocol.InsertTextFormat[item.insertTextFormat] == "PlainText" then
       return item.textEdit.newText
     else
       return M.parse_snippet(item.textEdit.newText)
     end
-  elseif item.insertText ~= nil then
+  elseif item.insertText ~= vim.NIL then
     if protocol.InsertTextFormat[item.insertTextFormat] == "PlainText" then
       return item.insertText
     else

この修正を行うことで,ようやく補完が出てくるようになりました.それなりに早くて快適.

Screen Shot 2020-07-24 at 17.02.11.png

ちなみに,ROS2のrclpyもさくさく補完できるようになりました.これは便利.

Screen Shot 2020-07-24 at 17.04.51.png

これは本当にPyCharmがいらなくなる日がくるかもしれない.

おまけ1

最終的には使いませんでしたが,pylsを使ってリンターの出力を消したときの設定も載せておきます.

nvim_lsp.pyls.setup{
  settings = {
    pyls = {
      plugins = {
        pyflakes = {enabled = false},
        pycodestyle = {enabled = false},
        pydocstyle = {enabled = false},
      }
    }
  }
}

おまけ2

jedi-language-serverでどんな設定が最終的にされているのかを確認するために使ったコードです.

参考: https://stackoverflow.com/a/27028488

function dump_impl(o, level)
  if type(o) == 'table' then
    local s = '{\n'
    for k, v in pairs(o) do
      if type(k) ~= 'number' then
        k = '"' .. k .. '"'
      end
      local indent = string.rep('  ', level + 1)
      s = s .. indent .. '['..k..'] = ' .. dump_impl(v, level + 1) .. ',\n'
    end
    local indent = string.rep('  ', level)
    return s .. indent .. '}'
  else
    return tostring(o)
  end
end
function dump(o)
  return dump_impl(o, 0)
end

local c = nvim_lsp.jedi_language_server.make_config()
print(dump(c))
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2