pmizio / typescript-tools.nvim

⚡ TypeScript integration NeoVim deserves ⚡
MIT License
1.39k stars 40 forks source link

Neovim 0.9.2 hangs on exit when setting loclist #164

Closed merijn closed 11 months ago

merijn commented 11 months ago

I have run into some cursed issue, I'm not sure how to diagnose/debug this situation, so please let me know what additional info is ready.

I prefer having my errors in the loclist and with this plugin that wasn't happening. In debugging this situation I discovered that manually updating the loclist via :lua vim.diagnostic.setloclist() with this plugin active causes neovim to hang indefinitely when quitting.

Attaching a debugger I see it hangs in:

* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x0000000100c4e6a0 nvim`ml_delete_int + 92
    frame #1: 0x0000000100ca8a74 nvim`qf_fill_buffer + 232
    frame #2: 0x0000000100ca7fac nvim`qf_update_buffer + 376
    frame #3: 0x0000000100cabb74 nvim`set_errorlist + 1360
    frame #4: 0x0000000100cae308 nvim`set_qf_ll_list + 308
    frame #5: 0x0000000100b9b380 nvim`call_internal_func + 144
    frame #6: 0x0000000100bb6998 nvim`call_func + 2064
    frame #7: 0x0000000100c27d3c nvim`nlua_call + 440
    frame #8: 0x0000000101082b04 libluajit-5.1.2.dylib`___lldb_unnamed_symbol348 + 44
    frame #9: 0x000000010108f4dc libluajit-5.1.2.dylib`lua_pcall + 148
    frame #10: 0x0000000100c28384 nvim`nlua_pcall + 120
    frame #11: 0x0000000100c28114 nvim`nlua_typval_exec + 224
    frame #12: 0x0000000100c28be8 nvim`ex_lua + 196
    frame #13: 0x0000000100bd6970 nvim`execute_cmd0 + 248
    frame #14: 0x0000000100bd37e0 nvim`do_cmdline + 11600
    frame #15: 0x0000000100b42a88 nvim`apply_autocmds_group + 1828
    frame #16: 0x0000000100b133bc nvim`nvim_exec_autocmds + 860
    frame #17: 0x0000000100b012bc nvim`nlua_api_nvim_exec_autocmds + 248
    frame #18: 0x0000000101082b04 libluajit-5.1.2.dylib`___lldb_unnamed_symbol348 + 44
    frame #19: 0x000000010108f4dc libluajit-5.1.2.dylib`lua_pcall + 148
    frame #20: 0x0000000100c28384 nvim`nlua_pcall + 120
    frame #21: 0x0000000100c2ad20 nvim`nlua_schedule_event + 104
    frame #22: 0x0000000100bc328c nvim`multiqueue_process_events + 92
    frame #23: 0x0000000100bc3b10 nvim`process_teardown + 228
    frame #24: 0x0000000100afaf48 nvim`event_teardown + 72
    frame #25: 0x0000000100afe5bc nvim`os_exit + 88
    frame #26: 0x0000000100afe4e0 nvim`getout + 916
    frame #27: 0x0000000100bdca10 nvim`ex_quit + 568
    frame #28: 0x0000000100bd6970 nvim`execute_cmd0 + 248
    frame #29: 0x0000000100bd37e0 nvim`do_cmdline + 11600
    frame #30: 0x0000000100c6ed5c nvim`nv_colon + 420
    frame #31: 0x0000000100c6c968 nvim`normal_execute + 4696
    frame #32: 0x0000000100d023ac nvim`state_enter + 356
    frame #33: 0x0000000100afd780 nvim`main + 10240
    frame #34: 0x0000000189f13f28 dyld`start + 2236

It seems to indefinitely spin inside nvim`ml_delete_int, but I have no idea why and whether this is a bug in neovim or inside this plugin.

This is neovim 0.9.2 from Homebrew on an Apple M1. I'm not sure what other info would be needed to figure out if this is a bug in the plugin or inside neovim?

merijn commented 11 months ago

Another smoking gun: This behaviour seems to only manifest when I have the following autocommand defined: au DiagnosticChanged * lua vim.diagnostic.setloclist({ open = false }).

This is interesting, because I started experimenting because DiagnosticChanged did not seem to fire when diagnostics were published by the LSP server, so something about how diagnostic publishing is handled seems wonky?

pmizio commented 11 months ago

Ok, I'm able to reproduce, but I'm still searching what is causing it. For now I'm sure this is some not easy to find edge case.

pmizio commented 11 months ago

@merijn I think I found problem and I it isn't related with plugin, but please check this for yourself and let me know. So, I was able to reproduce same bug in lua lsp with my plugin disabled. Problem occurs for me when I have enabled tool(null_ls for me) which do autoformat for me on save - in both my plugin and lua lsp. Additionally I found tailwindcss lsp attached to buffer(with or without my plugin) hang neovim with loclist open.

So I think it is something in nvim core or mentioned plugins/lsps.

I bet on core because to test I used fake data loclist instead calling vim.diagnostic.setloclist() and problem still show up. It may be some combination of loclist + DiagnosticChanged event + formatting maybe, I'm not sure.

pmizio commented 11 months ago

@merijn I was able to reproduce this using tailwind ls with minimal file below. Steps to reproduce:

  1. npm i -g @tailwindcss/language-server - install ls which cause problem
  2. open any ts file
  3. :_G.test() - to populate loclist
  4. :lopen
  5. :qa! - nvim hangs
--- CHANGE THESE
local pattern = "typescript"
local cmd = { "tailwindcss-language-server", "--stdio" }
-- Add files/folders here that indicate the root of a project
local root_markers = { ".git", ".editorconfig" }
-- Change to table with settings if required
local settings = vim.empty_dict()

vim.api.nvim_create_autocmd("FileType", {
  pattern = pattern,
  callback = function(args)
    local match = vim.fs.find(root_markers, { path = args.file, upward = true })[1]
    local root_dir = match and vim.fn.fnamemodify(match, ":p:h") or nil
    vim.lsp.start {
      name = "bugged-ls",
      cmd = cmd,
      root_dir = root_dir,
      settings = settings,
    }
  end,
})

_G.test = function()
  print "::::::::: debug message :::::::::"
  vim.fn.setloclist(0, {}, " ", {
    items = {
      {
        bufnr = 1,
        col = 1,
        end_col = 1,
        end_lnum = 12,
        lnum = 12,
        text = "Parsing error: Identifier expected.",
        type = "E",
      },
      {
        bufnr = 1,
        col = 1,
        end_col = 2,
        end_lnum = 12,
        lnum = 12,
        text = "Identifier expected.",
        type = "E",
      },
      {
        bufnr = 1,
        col = 26,
        end_col = 27,
        end_lnum = 18,
        lnum = 18,
        text = "Property 'Z' does not exist on type 'typeof TestEnum'.",
        type = "E",
      },
    },
    title = "Diagnostics",
  })
end

vim.api.nvim_create_autocmd('DiagnosticChanged', {
  pattern = '*.ts',
  callback = _G.test,
})

So it isn't related to my plugin it's something in core, if you want to use this mini file to report issue in core feel free to grab it.

merijn commented 11 months ago

Yeah, looking at the stack trace I was already wondering if it was maybe something in neovim itself, but I figured I'd try and rule out typescript-tools first :)

Thanks for the help, I'll make an issue on the neovim repo.

KostkaBrukowa commented 11 months ago

Hey @merijn . Sorry for bothering but do you have any tutorial or link or anything that could help me do debugging like you did (in the first post)? I have simmilar issue as you (hanging on quit), but I have no idea on how to do the debugging

merijn commented 11 months ago

@KostkaBrukowa All I did for that was lldb -p <nvim process id> to attach lldb to the hanging neovim and then hit bt to get a backtrace of whatever it was doing when I attached the debugger :)

Luckily the homebrew binary of neovim seems to ship with (some) debugging symbols to produce actually useful function names.

KostkaBrukowa commented 11 months ago

Wow. That's really helpful. Thank you very much!!