language-tools: svelte-language-server watcher doesn't work in neovim lspconfig

I’m in the same problem with my sveltekit project. I’m using typescript-svelte-plugin. Although typescript files (like +page.server.ts) works realtime, diagnostics of .svelte file does not updated.

I’m configuring root_pattern( {"package.json", "tsconfig.json", "tsconfig.jsonc", "node_modules"}) for svelte language server

https://user-images.githubusercontent.com/1560508/237040552-0a1be152-0c2b-45ab-b98c-3e927ffeae34.mov

_Originally posted by @ryoppippi in https://github.com/sveltejs/language-tools/issues/1415#issuecomment-1539681042_

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 35 (9 by maintainers)

Commits related to this issue

Most upvoted comments

Actually, you can just manually change the client capability in 0.9.x to have dynamicRegistration = true

local lsp_capabilities = vim.lsp.protocol.make_client_capabilities() --or whatever your setup requires
lsp_capabilities.workspace.didChangeWatchedFiles.dynamicRegistration = true

-- whatever your other plugin requires, for example:
-- lsp_capabilities.textDocument.completion = require('cmp_nvim_lsp').default_capabilities().textDocument.completion

lspconfig.svelte.setup {
    capabilities = lsp_capabilities,
}

If this still doesn’t work, please prepare a reproduction and report to neovim. Also, to reiterate, $/onDidChangeTsOrJsFile is not a substitution for file watcher, They both exist for a reason.

Okay, this is a truly hacky things, but I solved this problem with this setting

function on_attach(on_attach)
  vim.api.nvim_create_autocmd("LspAttach", {
    callback = function(args)
      local buffer = args.buf
      local client = vim.lsp.get_client_by_id(args.data.client_id)
      on_attach(client, buffer)
    end,
  })
end

on_attach(function(client, bufnr)
      vim.api.nvim_create_autocmd("BufWritePost", {
        pattern = { "*.js", "*.ts" },
        callback = function(ctx)
          if client.name == "svelte" then
            client.notify("$/onDidChangeTsOrJsFile", { uri = ctx.file })
          end
        end,
      })
    end)
end)

For people for whom the hack is still not working it might be because you are using ctx.file which when using telescope for example will be a relative path and not an absolute path. You can use ctx.match instead, and it fixed it for me.

on_attach = function(client, bufnr)
  vim.api.nvim_create_autocmd("BufWritePost", {
    pattern = { "*.js", "*.ts" },
    callback = function(ctx)
      -- Here use ctx.match instead of ctx.file
      client.notify("$/onDidChangeTsOrJsFile", { uri = ctx.match })
    end,
  })
end,

Make sure you include:

group = vim.api.nvim_create_augroup("svelte_ondidchangetsorjsfile", { clear = true }),

inside the 2nd param for nvim_create_autocmd function. Otherwise, new autocmd is created on every new buffer svelte lsp get attached to.

Thanks everyone for all the information. I got mine working by adding this into my on_attach() function:

                if client.name == "svelte" then
                    vim.api.nvim_create_autocmd("BufWritePost", {
                        pattern = { "*.js", "*.ts" },
                        group = svelte_augroup,
                        callback = function(ctx)
                            client.notify("$/onDidChangeTsOrJsFile", { uri = ctx.match })
                        end,
                    })
                end

I’m running

NVIM v0.9.5
Build type: Release
LuaJIT 2.1.1702233742

For anyone still struggling, I used following configuration in Astrovim and it worked

    config = {
      svelte = {
        capabilities = {
          workspace = {
            didChangeWatchedFiles = {
              dynamicRegistration = true,
            },
          },
        },
      },
    },

We can update @ryoppippi’s snippet to work without requiring the file to be saved to disk, replicating the behavior in the svelte-vscode extension. It would enable us to do the following:

  1. Assume foo.ts imports MyType from bar.svelte.
  2. Update MyType in foo.ts.
  3. Do not save foo.ts.
  4. bar.svelte is now aware of the latest changes made in step 2.
on_attach(function(client, bufnr)
-     vim.api.nvim_create_autocmd("BufWritePost", {
+     vim.api.nvim_create_autocmd({ "TextChanged", "TextChangedI", "TextChangedP" }, {
        pattern = { "*.js", "*.ts" },
        callback = function(ctx)
          if client.name == "svelte" then
            client.notify("$/onDidChangeTsOrJsFile", {
              uri = ctx.file,
+             changes = {
+               { text = table.concat(vim.api.nvim_buf_get_lines(ctx.buf, 0, -1, false), "\n") },
+             },
            })
          end
        end,
+       group = vim.api.nvim_create_augroup("svelte_ondidchangetsorjsfile", { clear = true }),
      })
    end)
end)

Some things I’m not sure of:

  1. In the original svelte-vscode implementation, the changes.range property is defined. However, I’m unsure as to how to define it in nvim. Nevertheless, this still works (maybe at the cost of some performance?) because “if only a text is provided it is considered to be the full content of the document.” (source).

  2. What is the best autocmd event(s) to use to balance performance and convenience. TBH, I’m not sure if we need to worry ourselves with performance at this point. I’m only mentioning this point due to the note in TextChanged’s description.


svelte-language-server: v0.16.1

$ nvim -v
NVIM v0.10.0-dev-7ca2d64
Build type: Release
LuaJIT 2.1.1693350652

@jasonlyu123 i install the last version but not working and fixed using example of @ryoppippi