Skip to content

Neovim 0,11: call to plines_win() may cause Nvim exits with no error #283

@lyokha

Description

@lyokha

Neovim version (nvim -v | head -n1)

NVIM v0.11.0

Operating system/version

Linux LLF2TDVV6 5.15.0-43-generic #46-Ubuntu SMP Tue Jul 12 10:30:17 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

How to reproduce the issue

I was not sure how to title this. Actually, I just wanted to update treesitter code for compatibility with Neovim 0.11. Here is a trivial diff:

diff --git a/lua/ufo/provider/treesitter.lua b/lua/ufo/provider/treesitter.lua
index d440075..83e379b 100644
--- a/lua/ufo/provider/treesitter.lua
+++ b/lua/ufo/provider/treesitter.lua
@@ -1,5 +1,6 @@
 local bufmanager = require('ufo.bufmanager')
 local foldingrange = require('ufo.model.foldingrange')
+local utils = require('ufo.utils')
 
 ---@class UfoTreesitterProvider
 ---@field hasProviders table<string, boolean>
@@ -107,7 +108,12 @@ local function iterFoldMatches(bufnr, parser, root, rootLang)
         for id, nodes in pairs(match) do
             local m = metadata[id]
             if m and m.range then
-                local type = nodes.type and nodes:type() or nil
+                local type
+                if utils.has11() then
+                    type = nodes[1].type and nodes[1]:type() or nil
+                else
+                    type = nodes.type and nodes:type() or nil
+                end
                 node = MetaNode:new(m.range, type)
             elseif type(nodes) ~= "table" then
                 -- old behaviou before 0.11
@@ -180,6 +186,9 @@ function Treesitter.getFolds(bufnr)
         self.hasProviders[ft] = false
         error('UfoFallbackException')
     end
+    if utils.has11() then
+        parser:parse()
+    end
 
     local ranges = {}
     local ok, matches = getCpatureMatchesRecursively(bufnr, parser)
diff --git a/lua/ufo/utils.lua b/lua/ufo/utils.lua
index b2c211a..8bf9c74 100644
--- a/lua/ufo/utils.lua
+++ b/lua/ufo/utils.lua
@@ -5,6 +5,18 @@ local fn = vim.fn
 local cmd = vim.cmd
 local uv = vim.loop
 
+---
+---@return fun(): boolean
+M.has11 = (function()
+    local has11
+    return function()
+        if has11 == nil then
+            has11 = fn.has('nvim-0.11') == 1
+        end
+        return has11
+    end
+end)()
+
 ---
 ---@return fun(): boolean
 M.has10 = (function()

Note that according to the release notes they did:

  • Query:iter_matches() correctly returns all matching nodes in a match instead of only the last node. This means that the returned table maps capture IDs to a list of nodes that need to be iterated over. For backwards compatibility, an option all=false (only return the last matching node) is provided that will be removed in a future release.

  • vim.treesitter.get_parser() and vim.treesitter.start() no longer parse the tree before returning. Scripts must call LanguageTree:parse() explicitly.

    local p = vim.treesitter.get_parser(0, 'c')
    p:parse()

Hence the changes.

I use ufo to fold code blocks in markdown files on startup. It looks like

Image

In Neovim 0.11 they, unfortunately, removed delimiters of code blocks with conceal_lines but I customized the query and returned the view.

The issue I found is that sometimes, once in 6-7 runs, nvim abruptly exits with succesfull error code ($? is 0) just after ufo successfully have rendered the folds. This happens in a blink, but I see that the folds get rendered.

My first thought was that this is related to

  • Treesitter folding is now calculated asynchronously.

But this wasn't the case as I tried to use vim.g._ts_force_sync_parsing = true but nvim still exited. I began to trace ufo using log.error() and found that nvim exits during repetitive calls in

            size = lsizeObj:size(i)

This line calls pline_win() via LFFI object. I tried to replace this by LNonFFI in code: the exits have gone. I returned to LFFI and finally came to this:

diff --git a/lua/ufo/wffi.lua b/lua/ufo/wffi.lua
index 591edad..7125a9a 100644
--- a/lua/ufo/wffi.lua
+++ b/lua/ufo/wffi.lua
@@ -19,7 +19,8 @@ end
 ---@return number
 function M.plinesWin(winid, lnum)
     local wp = findWin(winid)
-    return C.plines_win(wp, lnum, true)
+    local n = C.plines_win(wp, lnum, true)
+    return n
 end
 
 ---

Surprisingly to me, the exits have gone. I cannot explain how this affects the behaviour as I do not know Lua internalls well. Perhaps this is a transitory bug or something related to tail recursion. I never experienced this in Neovim 0.10, so it could be a bug of Neovim 0.11.

Expected behavior

No unexpected exits.

Actual behavior

Nvim exits unexpectedly sometimes. There is a solution (or maybe workaround), see above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions