nvim-treesitter/nvim-treesitter-context

Regression: some other things are broken at startup with `syntax on`

9ary opened this issue · 1 comments

9ary commented

Description

I noticed some things such as treesitter syntax highlighting and .editorconfig weren't applying at startup (when passing files as arguments to nvim).

I tracked the culprit down to this plugin and bisected the issue. The problematic commit is 2484f58. It seems reverting the function M.get() in that file fixes it.

Neovim version

0.9.5 and 0.10.0

Expected behavior

No response

Actual behavior

Things break on first read from command line.

Minimal config

local plugins = {
  ts         = 'https://github.com/nvim-treesitter/nvim-treesitter',
  ts_context = 'https://github.com/nvim-treesitter/nvim-treesitter-context',
  -- ADD ADDITIONAL PLUGINS THAT ARE _NECESSARY_ TO REPRODUCE THE ISSUE
}

for name, url in pairs(plugins) do
  local install_path = '/tmp/nvim/site/'..name
  if vim.fn.isdirectory(install_path) == 0 then
    vim.fn.system { 'git', 'clone', '--depth=1', url, install_path }
  end
  vim.o.runtimepath = install_path..','..vim.o.runtimepath
end

-- ADD INIT.LUA SETTINGS THAT IS _NECESSARY_ FOR REPRODUCING THE ISSUE

vim.cmd [[syntax on]]
require("treesitter-context").setup {
}

Steps to reproduce

An easy way to repro is to have a .editorconfig file like this:

root = true

[*]
max_line_length = 99

Open a file like nvim foo.c, and run :set tw?. With ts-context enabled, this returns 0, while without it returns 99 as expected.

This doesn't repro when reading files with :e.

9ary commented

Figured it out.

Call chain:



local context, context_lines = get_context(bufnr, winid)

return require('treesitter-context.context').get(bufnr, winid)

if not pcall(vim.treesitter.get_parser, bufnr) then

into neovim code:
https://github.com/neovim/neovim/blob/6c3f7e7e27a0ffcf6d58dc1f5ad2fce7e59a2d88/runtime/lua/vim/treesitter.lua#L108
https://github.com/neovim/neovim/blob/6c3f7e7e27a0ffcf6d58dc1f5ad2fce7e59a2d88/runtime/lua/vim/treesitter.lua#L39

Indeed, minimal repro with no plugins:

bufnr = vim.api.nvim_get_current_buf()
vim.fn.bufload(bufnr)
local group = vim.api.nvim_create_augroup('testgroup', {})
vim.api.nvim_create_autocmd({ 'BufNewFile', 'BufRead', 'BufFilePost' }, {
  group = group,
  callback = function(args)
    print("hello world")
  end,
})

The autocmd never fires, because it was registered after bufload() was called!

The reason why this doesn't happen with syntax off is because vim.treesitter.get_parser() can't figure out the file's language in that case, and errors out.

Solution:

diff --git a/lua/treesitter-context/context.lua b/lua/treesitter-context/context.lua
index 5339c80..aaf5ae6 100644
--- a/lua/treesitter-context/context.lua
+++ b/lua/treesitter-context/context.lua
@@ -253,6 +253,14 @@ end
 --- @param winid integer
 --- @return Range4[]?, string[]?
 function M.get(bufnr, winid)
+  -- vim.treesitter.get_parser() calls bufload(), but we don't actually want to load the buffer:
+  -- this method is called during plugin init, before other plugins or the user's config
+  -- have a chance to initialize.
+  -- They may want to register autocmds, and this would prevent them from firing.
+  if vim.fn.bufloaded(bufnr) == 0 then
+    return
+  end
+
   if not pcall(vim.treesitter.get_parser, bufnr) then
     return
   end

I'll open a PR.

Also, the reason why this regressed. This is what it looked like before:

function M.get(bufnr, winid)
local max_lines = calc_max_lines(winid)
if max_lines == 0 then
return
end
if not pcall(vim.treesitter.get_parser, bufnr) then
return
end

calc_max_lines() always returns 0 at startup since the cursor is at the top of the window. This accidentally guarded get_parser() from being called so early, but it was removed in that commit.