lukas-reineke / indent-blankline.nvim

Indent guides for Neovim
MIT License
4.16k stars 102 forks source link

Lags in a file with a large block comment and treesitter #843

Closed drybalka closed 7 months ago

drybalka commented 7 months ago

Problem

Moving cursor with any movement lags quite heavily in a file with a large block comment.

Steps to reproduce

min-init.lua

require('ibl').setup {}
require('nvim-treesitter.configs').setup {
  highlight = {
    enable = true,
  },
}

Using this config in a file such as below leads to lags.

large_comment.scala

/*
  test("Exercise 8.4")(ExhGen.int ** ExhGen.int ** genRNG):
    case n ** m ** rng =>
      val (start, stopExclusive) = if n < m then (n, m) else (m, n)
      val (k, _) = Gen.choose(start, stopExclusive).next(rng)
      assert(start <= k && k <= stopExclusive)

  test("Exercise 8.5, unit")(ExhGen.int ** genRNG):
    case n ** rng0 =>
      val genUnit = Gen.unit(n)
      val (n1, rng1) = genUnit.next(rng0)
      assertEquals(n1, n)
      val (n2, _) = genUnit.next(rng1)
      assertEquals(n2, n)

  test("Exercise 8.5, boolean + listOfN")(genShortNumber ** genRNG):
    case n ** rng0 =>
      val (randomBooleanList, rng1) = Gen.boolean.listOfN(shortSample).next(rng0)
      assert(randomBooleanList.contains(true), "'Gen.boolean' should not generate only 'false' values")
      assert(randomBooleanList.contains(false), "'Gen.boolean' should not generate only 'true' values")

      val (randomBooleanList1, _) = Gen.boolean.listOfN(n).next(rng1)
      assertEquals(randomBooleanList1.length, n)

  test("Exercise 8.6, flatMap")(ExhGen.int ** genRNG):
    case n ** rng =>
      val genA = Gen.unit(n)
      def aToGenB(a: Int) = Gen.unit(a % 2 == 0)
      val (isEven, _) = genA.flatMap(aToGenB).next(rng)
      assertEquals(n % 2 == 0, isEven)

  test("Exercise 8.6, listOfN")(genShortNumber ** genRNG):
    case n ** rng =>
      val (randomBooleanList, _) = Gen.boolean.listOfN(Gen.unit(n)).next(rng)
      assertEquals(randomBooleanList.length, n)

  test("Exercise 8.7")(ExhGen.int ** ExhGen.int ** genRNG):
    case n ** m ** rng =>
      val genUnion = Gen.union(Gen.unit(n), Gen.unit(m))
      val genUnionList = genUnion.listOfN(shortSample)
      val (unionList, _) = genUnionList.next(rng)
      assert(unionList.count(_ == n) >= shortSample / 3, "Values should be extracted with approximately equal likelihood")
      assert(unionList.count(_ == m) >= shortSample / 3, "Values should be extracted with approximately equal likelihood")

  test("Exercise 8.8")(ExhGen.int ** ExhGen.int ** genRNG):
    case n ** m ** rng =>
      val genUnion0 = Gen.weighted((Gen.unit(n), 0.0), (Gen.unit(m), 1.0))
      val (unionList0, _) = genUnion0.listOfN(shortSample).next(rng)
      assertEquals(unionList0.count(_ == n), 0, "g1 weights 0")
      assertEquals(unionList0.count(_ == m), shortSample, "g1 weights 0")

      val genUnion1 = Gen.weighted((Gen.unit(n), 1.0), (Gen.unit(m), 0.0))
      val (unionList1, _) = genUnion1.listOfN(shortSample).next(rng)
      assertEquals(unionList1.count(_ == n), shortSample, "g2 weights 0")
      assertEquals(unionList1.count(_ == m), 0, "g2 weights 0")

      val genUnion2 = Gen.wei
 Hooks provide a way to extend the functionality of indent-blankline. Either
 from your own config, or even from other third part plugins.
 Hooks consist of a type (|ibl.hooks.type|) and a callback
 function (|ibl.hooks.cb|). When indent-blankline computes values for which
 hooks exist, for example if a buffer is active, it then calls all registered
 hooks for that type to get the final value.
ghted((Gen.unit(n), 0.5), (Gen.unit(m), 0.5))
      val (unionList2, _) = genUnion2.listOfN(shortSample).next(rng)
      assert(unionList2.count(_ == n) >= shortSample / 3, "g1 and g2 have the same weight")
      assert(unionList2.count(_ == m) >= shortSample / 3, "g1 and g2 have the same weight")

      val genUnion3 = Gen.weighted((Gen.unit(n), 0.33), (Gen.unit(m), 0.67))
      val (unionList3, _) = genUnion3.listOfN(shortSample).next(rng)
      assert(unionList3.count(_ == n) >= shortSample / 5, "g2 is twice as common as g1")
      assert(unionList3.count(_ == m) >= shortSample / 2, "g2 is twice as common as g1")
*/

Expected behavior

Ibl should not lag.

Neovim version (nvim -v)

NVIM v0.9.5

lukas-reineke commented 7 months ago

The performance bottleneck here is treesitter, not indent-blankline, there is nothing I can do. You can turn off scope to not use treesitter queries.

drybalka commented 7 months ago

Thank you for the quick reply!

Can you please explain a bit more how this is a treesitter issue, so that I could create an issue on their board? Do you by any chance know why treesitter-powered highlighting works without lags, but indent-blankline cannot? And could you please clarify why exactly this is their issue and there is nothing you can do about it, so that they cannot simply dismiss me with "treesitter works without lags for us (highlighting, for example), so the problem must be downstream".

I tried turning off the scope in ibl, as you suggested, but it had no effect on the issue. Do you have any other suggestions?

lukas-reineke commented 7 months ago

Can you please explain a bit more how this is a treesitter issue, so that I could create an issue on their board?

The only part in indent-blankline that is related to syntax, such as a big comment, is scope. And scope is handled by treesitter. Indent blankline simply calls treesitter to get the current scope. So if you have performance issues only with big comments, all I can say is that is has to be caused by treesitter. You don't provide enough information for me to say anything more.

Do you by any chance know why treesitter-powered highlighting works without lags, but indent-blankline cannot?

Not the same thing. Treesitter does more than just highlighting. In this case it provides the scope.

drybalka commented 7 months ago

Thank you for answering! I will gladly provide you with more information, I just assumed that the minimal config and an example file where this happens would be enough. What else do you need to reproduce the issue? Can you reproduce it at all? I get the same behavior also with the following config, so the issue should not be in the scope feature:

require("ibl").setup({
    scope = {
        enabled = false,
    },
})
require("nvim-treesitter.configs").setup({
    highlight = {
        enable = true,
    },
})

And just to clarify, I do not have any issues with the following config:

require("ibl").setup({
    enabled = false,
})
require("nvim-treesitter.configs").setup({
    highlight = {
        enable = true,
    },
})

And lastly, which is kinda weird, I also do not have any problems when disabling the highlighting in treesitter:

require("ibl").setup({})
require("nvim-treesitter.configs").setup({
    highlight = {
        enable = false,
    },
})
lukas-reineke commented 7 months ago

Can you reproduce it at all?

The example you shared does not lag for me, but performance depends on a lot of factors.

I get the same behavior also with the following config, so the issue should not be in the scope feature

There is no other logic in indent-blankline that depends on syntax. If turning off scope doesn't fix it, reevaluate your first assumption that it is caused by comments.

Sorry, I don't want to be dismissive, but "it lags" is just not enough information for me to do anything with.

You can try https://github.com/stevearc/profile.nvim to see where time is spent.