🐍

nvim-treesitter は Python のインデントを壊す (共存方法まで紹介)

2024/05/27に公開

はじめに

nvim-treesitterを導入していると、たまに Python のインデントがバグります。

  • oによる改行でのインデントがおかしくなっている様子

仕組み上仕方のないコンフリクトなんですが、初見だと戸惑いますし何が原因か分からないかと思います。

本記事では

  • なぜ起きるのか
  • どうやって回避するのか

について説明します。

原因

原因になる行はこういうものです。

if s == "(":

文字列の ( なんかが含まれる行ですね。

組み込みや Vimjas/vim-python-pep8-indent による Python のインデント計算は、シンタックスハイライトを参照することがあります。
この辺 とか この辺 とかですね。

Python は () などで行継続できるのでインデントに影響しますが、これが文字列中にあるのなら無視するべきです。
これを判断するためにシンタックスハイライトを見ます。

x = (2 +
     4 * 10**1)

ところが Treesitter を有効化していると、通常のハイライトが無効化されてしまいます。
色の付け方の仕組みが違うので、synID() は何も返しません。
そうしてインデント計算が壊れるわけです。

if s == "(":
          |ここにカーソル来るはず!

回避方法

最もシンプルな解決方法は、Python で treesitter を無効化することです。

がっかりしましたか?
安心してください、もっと良い解決方法が用意されています。

syntax も動かす

幸いにもこのコンフリクトは nvim-treesitter 開発チームも把握しています。

require("treesitter.configs").setup({
  highlight = {
    enable = true,
    additional_vim_regex_highlighting = { "python" },
  },
})

highlight.additional_vim_regex_highlighting というオプションを有効化することで、裏で syntax も計算してくれます。
これにより、treesitter のハイライトを残しつつ、インデント計算も正常に行なわれるようになります。

なお、処理が増える分重くなることには注意してください。

treesitter にインデント計算させる

experimental な機能ですが nvim-treesitter にインデント計算させることもできます。
使用者によると割と安定してるらしいので、こちらの方がいいかもしれないです。

require("treesitter.configs").setup({
  indent = {
    enable = true,
    -- python だけで有効化したいなら
    -- disable = function(lang)
    --   return lang ~= "python"
    -- end
  },
})

おわり

Python のインデントがおかしくなったからって、treesitter 疑うのは難しいですよねぇ。
誰かの助けになれば幸いです。

GitHubで編集を提案

Discussion