vuejs / language-tools

⚡ High-performance Vue language tooling based-on Volar.js
https://marketplace.visualstudio.com/items?itemName=Vue.volar
MIT License
5.62k stars 378 forks source link

Version 2 stop working with nvim lsp #3925

Closed RayGuo-ergou closed 4 months ago

RayGuo-ergou commented 4 months ago

Update: check readme.


tldr:

local mason_registry = require('mason-registry')
local ts_plugin_path = mason_registry.get_package('vue-language-server'):get_install_path() .. '/node_modules/@vue/language-server/node_modules/@vue/typescript-plugin'

local servers = {
  tsserver = {
    init_options = {
      plugins = {
        {
          name = '@vue/typescript-plugin',
          location = ts_plugin_path,
          -- If .vue file cannot be recognized in either js or ts file try to add `typescript` and `javascript` in languages table.
          languages = { 'vue' },
        },
      },
    },
    filetypes = { 'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue' },
  },
  volar = {},
}

local mason_lspconfig = require('mason-lspconfig')

-- Auto cmd (LspAttach) to setup keybind, codelens, and formatting stuff
-- I assume everyone should have this configured already but just for reference
-- @see https://github.com/RayGuo-ergou/dotfiles/blob/cdf866790b1daa27444bd9991025740c8eb74c5b/nvim/lua/ergou/util/lsp.lua#L43
Util.lsp.lsp_autocmd()

local capabilities = vim.lsp.protocol.make_client_capabilities()
-- If you need cmp
capabilities = vim.tbl_deep_extend('force', capabilities, require('cmp_nvim_lsp').default_capabilities())
mason_lspconfig.setup({
ensure_installed = vim.tbl_keys(servers),
handlers = {
    function(server_name)
    local server = servers[server_name] or {}
    server.capabilities = vim.tbl_deep_extend('force', {}, capabilities, server.capabilities or {})
    require('lspconfig')[server_name].setup(server)
    end,
},
})

Hi,

I am having issue to run volar@2.0.1 with neovim lsp.

cmd: vue-language-server --stdio

With 1.8.27: image image image

With 2.0.1: image image image

johnsoncodehk commented 4 months ago

After 2.0, typescript support is fully implemented through typescript plugin. For IDEs other than VSCode, you need to install @vue/typescript-plugin(https://www.npmjs.com/package/@vue/typescript-plugin) separately, which will work with @vue/language-server.

I'm not sure how nvim configures the typescript plugin, if nvim can't configure it, you need to install @vue/typescript-plugin to the project or globally, and then configure it in tsconfig.

{
    "compilerOptions": {
        "plugins": [{ "name": "@vue/typescript-plugin" }]
    }
}
RayGuo-ergou commented 4 months ago

Hi @johnsoncodehk Thanks for your reply but I don't think the issue is caused by typescript as I created a new project without typescript using vite-create-vue, I still do not get auto completion and other cool stuffs.

"dependencies": {
    "vue": "^3.4.19"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.4",
    "vite": "^5.1.4"
  }

Never looked into volar source code but my guessing is that something's off with the communication between volar server and nvim lsp client.

I think I will just live with old version 1.8.27 for now.

BitInByte commented 4 months ago

Hey, I'm also facing the exact same issues. None of the lsp functionality works, even though it is able to attach successfully. I can also say that previously, the last version I had before updating was working without any issue

adriaanbaelus commented 4 months ago

Same here, the language server is running and attached to my vue file, but completely nonfunctional. Like @RayGuo-ergou, I've downgraded to 1.8.27 for now.

@johnsoncodehk I'm not clear on how the vue language server works, but for most neovim users, volar is installed globally with Mason, a sort of package manager for language servers. It installs a specific version of @vue/language-server in a specific location. The next step is configuring the language server, which is usually done using nvim-lspconfig. In practice, it runs (the previously installed) @vue/language-server/bin/vue-language-server.js --stdio and passes the typescript tsdk as initializationOptions. I'm guessing the default configuration there no longer works with the 2.0 release, but I have no idea what configuration is needed to get it right. Is there any documentation on how to get the 2.x language server configured and running?

WhyNotHugo commented 4 months ago

Upgrading the LSP to 2.0.3 on neovim works for me. Note that the 2.0.0 release was broken, so be sure to install the latest patch version.

To confirm that the LSP is working, I opened a SFC and removed a <, at which point the LSP indicated an error in the corresponding end tag.

WhyNotHugo commented 4 months ago

I have installed @vue/typescript-plugin, but TypeScript support won't work for me.

Is it loaded automatically by the LSP? Any documentation/guide/example would be most welcome.

WhyNotHugo commented 4 months ago

packages/language-server/lib/types.ts defines initialisation options:

export type VueInitializationOptions = InitializationOptions & {
    typescript: {
        tsdk: string;
    }
    vue?: {
        /**
         * @example ['vue1', 'vue2']
         */
        additionalExtensions?: string[];
    };
};

The InitializationOptions interface is defined in https://github.com/volarjs/volar.js in packages/language-server/lib/types.ts:

export interface InitializationOptions {
    l10n?: {
        location: string; // uri
    };
    diagnosticModel?: DiagnosticModel;
    maxFileSize?: number;
    /**
     * Extra semantic token types and modifiers that are supported by the client.
     */
    semanticTokensLegend?: vscode.SemanticTokensLegend;
    codegenStack?: boolean;
}

The only relevant thing that I see is the typescript/tsdk field, but that one is not new, so I don't think that it is necessary. I don't see any obvious way to specify plug-ins, so maybe they don't need to be explicitly registered?

RayGuo-ergou commented 4 months ago

Hi @WhyNotHugo Thanks for your sharing, I have upgraded to 2.0.3 and some feature is back! (like the error check you mentioned) image

But all javascript related things still not working for me. (e.g. go to definition, go to reference and lsp hover like ref) image image

Just asking are these things work for you in a javascript project?

WhyNotHugo commented 4 months ago

I have not tried a javascript project yet. I tried a typescript project, and error diagnostics only show up for the html template portion, but not for typescript code.

jblyberg commented 4 months ago

I was able to get everything working with 2.0.3. Here is my config (note, I use neoconf to tell lspconfig I'm using a volar project). I am also using typescript-tools instead of tsserver.

{
    "neovim/nvim-lspconfig",
    dependencies = {
      "pmizio/typescript-tools.nvim",
    },
    opts = {
      servers = {
        tsservercontext = {},
      },

      setup = {
        tsservercontext = function(_, opts)
          local neoconf = require("neoconf")
          local lspconfig = require("lspconfig")

          if neoconf.get("is-volar-project") then
            lspconfig["volar"].setup({
              server = opts,
              settings = {},
            })

            require("typescript-tools").setup({
              server = opts,
              settings = {
                tsserver_plugins = {
                  "@vue/typescript-plugin",
                },
              },
              filetypes = {
                "javascript",
                "typescript",
                "vue",
              },
            })
          else
            require("typescript-tools").setup({
              server = opts,
            })
          end

          return true
        end,
      },
    },
  }

Note specifically:

tsserver_plugins = {
  "@vue/typescript-plugin",
}

This works fine, however, volar still tries to fetch definitions in .vue files, so I get a "No information available" notice.

chaozwn commented 4 months ago

I was able to get everything working with 2.0.3. Here is my config (note, I use neoconf to tell lspconfig I'm using a volar project). I am also using typescript-tools instead of tsserver.

{
    "neovim/nvim-lspconfig",
    dependencies = {
      "pmizio/typescript-tools.nvim",
    },
    opts = {
      servers = {
        tsservercontext = {},
      },

      setup = {
        tsservercontext = function(_, opts)
          local neoconf = require("neoconf")
          local lspconfig = require("lspconfig")

          if neoconf.get("is-volar-project") then
            lspconfig["volar"].setup({
              server = opts,
              settings = {},
            })

            require("typescript-tools").setup({
              server = opts,
              settings = {
                tsserver_plugins = {
                  "@vue/typescript-plugin",
                },
              },
              filetypes = {
                "javascript",
                "typescript",
                "vue",
              },
            })
          else
            require("typescript-tools").setup({
              server = opts,
            })
          end

          return true
        end,
      },
    },
  }

Note specifically:

tsserver_plugins = {
  "@vue/typescript-plugin",
}

This works fine, however, volar still tries to fetch definitions in .vue files, so I get a "No information available" notice.

My thoughts are the same as yours: typescript-tools.nvim is used for handling ts and js files, while volar is used for handling vue files. However, it seems that there are currently issues with volar.

RayGuo-ergou commented 4 months ago

I got the lsp working with only typscript-tool plugin ( so no volar notify upon hover ). Huge thanks to @jblyberg.

image image image

My config:

      mason_lspconfig.setup({
        ensure_installed = vim.tbl_keys(servers),
        handlers = {
          function(server_name)
            local server = servers[server_name] or {}
            server.on_attach = on_attach
            server.capabilities = vim.tbl_deep_extend('force', {}, capabilities, server.capabilities or {})
            -- inherit my volar settings, you can just add vue to the `typescript-tools` filetypes.
            if server_name == 'volar' then
              require('typescript-tools').setup(server)
            else
              require('lspconfig')[server_name].setup(server)
            end
          end,
        },
      })

The @vue/typescript-plugin need to be defined in tsconfig.json as Johnson mentioned. ( make sure you have it installed)

{
    "compilerOptions": {
        "plugins": [{ "name": "@vue/typescript-plugin" }]
    }
}
WhyNotHugo commented 4 months ago

Oh, I had assumed that "typescript plugin" meant "a plugin that adds typescript support to this language server".

Did I misunderstand this and "typescript plugin" is a actually plugin for tsserver that adds vue support to it?

I'm a bit confused about volar's role if that's the case. If the typescript plugin gives tsserver the ability to handle vue code, why do I still need to keep around volar?

jblyberg commented 4 months ago

I'm a bit confused about volar's role if that's the case. If the typescript plugin gives tsserver the ability to handle vue code, why do I still need to keep around volar?

I believe that volar provides language server support inside template tags and is also required by the vue typescript plugin.

WhyNotHugo commented 4 months ago

I installed @vue/typescript-plugin together with tsserver, but it still won't yield error diagnostics for a SFC file.

I'm taking a pretty straightforward approach here:

  tsserver = {
    -- I installed @vue/typescript-plugin inside this container:
    cmd = lsp_containers.command("tsserver"),
    settings = {
      tsserver_plugins = {
        "@vue/typescript-plugin",
      },
    },
    filetypes = {
      "javascript",
      "typescript",
      "vue",
    },
  },

For regular typescript files, tsserver can't seem to resolve those SFC. E.g.: for line import Header from "./components/Header.vue";, it shows:

Cannot find module './components/Header.vue' or its corresponding type declarations.
chaozwn commented 4 months ago

I got the lsp working with only typscript-tool plugin ( so no volar notify upon hover ). Huge thanks to @jblyberg.

image image image

My config:

      mason_lspconfig.setup({
        ensure_installed = vim.tbl_keys(servers),
        handlers = {
          function(server_name)
            local server = servers[server_name] or {}
            server.on_attach = on_attach
            server.capabilities = vim.tbl_deep_extend('force', {}, capabilities, server.capabilities or {})
            -- inherit my volar settings, you can just add vue to the `typescript-tools` filetypes.
            if server_name == 'volar' then
              require('typescript-tools').setup(server)
            else
              require('lspconfig')[server_name].setup(server)
            end
          end,
        },
      })

The @vue/typescript-plugin need to be defined in tsconfig.json as Johnson mentioned. ( make sure you have it installed)

{
    "compilerOptions": {
        "plugins": [{ "name": "@vue/typescript-plugin" }]
    }
}

image We have the same configuration, so why am I getting a tsserver error?

WhyNotHugo commented 4 months ago

Does @vue/typescript-plugin need to be installed with tsserver or within the current project's node_modules?

chaozwn commented 4 months ago

Does @vue/typescript-plugin need to be installed with tsserver or within the current project's node_modules?

you must use typescript-tools.nvim replace tsserver.

jblyberg commented 4 months ago

Does @vue/typescript-plugin need to be installed with tsserver or within the current project's node_modules?

What I've found (and I spent way too much time on this yesterday) is that tsserver doesn't (at least for me) load the vue typescript plugin. You can try for yourself. Look at the tsserver docs https://github.com/typescript-language-server/typescript-language-server/blob/master/docs/configuration.md .. You can specify plugin settings under initializationOptions but that doesn't seem to work. This issue seems to indicate that others have trouble with that setting, however, and I couldn't get tsserver to load that plugin. the typescript-tools package is more explicit about how to load tsconfig plugins and works, so I went with that.

WhyNotHugo commented 4 months ago

Sounds like loading plugins via tsserver is problematic or non-trivial. But the devs here must have figured out a way to load the plugin to test it and use it themselves. typescript-tools.nvim is neovim-specific, I don't think they'd target that exclusively.

WhyNotHugo commented 4 months ago

Oh, actually, what I'm using is typescript-language-server, not tsserver.

WhyNotHugo commented 4 months ago

Apparently the location field is also required when defining plugins: https://github.com/typescript-language-server/typescript-language-server/blob/b224b878652438bcdd639137a6b1d1a6630129e4/docs/configuration.md?plain=1#L27-L31

gegoune commented 4 months ago

you must use typescript-tools.nvim replace tsserver.

Are you saying that there currently is no way to make it work with tsserver or that above configuration targets typescript-tools.nvim?

I would rather not switch to software which warns about its early beta stage just yet.

jblyberg commented 4 months ago

I think it's entirely probable that I am just not initializing tsserver correctly--which I think is a documentation issue. As @johnsoncodehk said, non-VSCode editors have to handle this manually.

jblyberg commented 4 months ago

Apparently the location field is also required when defining plugins: https://github.com/typescript-language-server/typescript-language-server/blob/b224b878652438bcdd639137a6b1d1a6630129e4/docs/configuration.md?plain=1#L27-L31

Setting the location did not work for me either. Check out this issue which suggests that you can also just put anything in there like so:

plugins = {
  {
    name = "anything";
    location = "anything";
  };
};

That did not work either.

WhyNotHugo commented 4 months ago

I made it work! :tada:

  tsserver = {
    cmd = lsp_containers.command("tsserver"),
    init_options = {
      plugins = {
        {
          name = "@vue/typescript-plugin",
          location = "/usr/local/lib/node_modules/@vue/typescript-plugin",
          languages = {"typescript", "vue"},
        },
      },
    },
    filetypes = {
      "javascript",
      "typescript",
      "vue",
    },
  },

This shows error diagnostics on the <script> portion of SFC files.

chaozwn commented 4 months ago

I got the lsp working with only typscript-tool plugin ( so no volar notify upon hover ). Huge thanks to @jblyberg.

image image image

My config:

      mason_lspconfig.setup({
        ensure_installed = vim.tbl_keys(servers),
        handlers = {
          function(server_name)
            local server = servers[server_name] or {}
            server.on_attach = on_attach
            server.capabilities = vim.tbl_deep_extend('force', {}, capabilities, server.capabilities or {})
            -- inherit my volar settings, you can just add vue to the `typescript-tools` filetypes.
            if server_name == 'volar' then
              require('typescript-tools').setup(server)
            else
              require('lspconfig')[server_name].setup(server)
            end
          end,
        },
      })

The @vue/typescript-plugin need to be defined in tsconfig.json as Johnson mentioned. ( make sure you have it installed)

{
    "compilerOptions": {
        "plugins": [{ "name": "@vue/typescript-plugin" }]
    }
}

null-ls format working properly?

jblyberg commented 4 months ago

I made it work! 🎉 This shows error diagnostics on the <script> portion of SFC files.

Interesting. I had not tried installing the plugin globally. I'd rather not have to do that but I'll give it a shot.

WhyNotHugo commented 4 months ago

Interesting. I had not tried installing the plugin globally. I'd rather not have to do that but I'll give it a shot.

You'll note that I'm overriding cmd; I'm running the LSP in a container, so it's "globally" inside that container.

adriaanbaelus commented 4 months ago

I made it work! 🎉 This shows error diagnostics on the <script> portion of SFC files.

Interesting. I had not tried installing the plugin globally. I'd rather not have to do that but I'll give it a shot.

Perhaps @vue/typescript-plugin needs to be added as a dependency for vue-language-server in Mason? Considering the vue-language-server is mostly nonfunctional without the typescript plugin (and typescript is already a dependency), that would at least provide a consistent location for the global install (and it would stay in sync when upgrading vue-language-server).

jblyberg commented 4 months ago

OK, I was able to make it work with tsserver with a configuration derived from what @WhyNotHugo was doing. The trick was explicitly adding vue to the languages property under plugins. It turns out can can just put anything in the location field and it will look the the project root node_modules

tsserver = {
  init_options = {
    hostInfo = "neovim",
    plugins = {
      {
        name = "@vue/typescript-plugin",
        location = "anything",
        languages = {
          "typescript",
          "vue",
        },
      },
    },
  },
  filetypes = {
    "javascript",
    "typescript",
    "vue",
  },
},
jblyberg commented 4 months ago

As a general note to the maintainers, I do think Volar should have an option to silently fail when queried. Now that takeover mode has been removed, it's irritating to see the "No information available" notices.

flytaly commented 4 months ago

The tsserver works fine for me with the configuration above. However, the typescript-tools for some reason throw the following error on some files within the Vue template. It happens during normal scrolling with the j/k keys. v0.9.5 image

or in v0.10 image

jblyberg commented 4 months ago

The tsserver works fine for me with the configuration above. However, the typescript-tools for some reason throw the following error on some files within the Vue template. It happens during normal scrolling with the j/k keys. v0.9.5

I don't think this is an issue with vue language tools, but rather the interaction between typescript-tools and nvim-treesitter.

chaozwn commented 4 months ago

The tsserver works fine for me with the configuration above. However, the typescript-tools for some reason throw the following error on some files within the Vue template. It happens during normal scrolling with the j/k keys. v0.9.5 image

or in v0.10 image

i have same problem.

johnsoncodehk commented 4 months ago

For the problem where __VLS_xxx errors are being shown in SFC, it is most likely due to a lack of jsconfig/tsconfig rather than a configuration issue. See #3942.

BitInByte commented 4 months ago

Hey @WhyNotHugo that solution seems promising, however, some people uses typescript-tools instead of tsserver. Is there anywhere on typescript-tools where we can apply this settings? Or we need to rather use tsserver only?

WhyNotHugo commented 4 months ago

Hey @WhyNotHugo that solution seems promising, however, some people uses typescript-tools instead of tsserver. Is there anywhere on typescript-tools where we can apply this settings? Or we need to rather use tsserver only?

Try passing the same init_options to require("typescript-tools").setup and see if that works? E.g.:

require("typescript-tools").setup({init_options = ...})
chaozwn commented 4 months ago

it seems volar not works in <template #icon> syntax.

image

chaozwn commented 4 months ago

it seems volar not works in <template #icon> syntax.

image

image

BitInByte commented 4 months ago

Hey @WhyNotHugo that solution seems promising, however, some people uses typescript-tools instead of tsserver. Is there anywhere on typescript-tools where we can apply this settings? Or we need to rather use tsserver only?

Try passing the same init_options to require("typescript-tools").setup and see if that works? E.g.:

require("typescript-tools").setup({init_options = ...})

Haven't worked, is there anything that I need to install with that?

RayGuo-ergou commented 4 months ago

Did not want to add more plugins but could not find a way to use the plugin with tsserver. @WhyNotHugo Thank you so much!

RayGuo-ergou commented 4 months ago

And I think we still need volar running with tsserver. Just noticed without volar some vue things do not work, e.g. v-if.

I am using folke/noice.nvim and set

lsp ={
        hover = {
          silent = true,
        },
}

to avoid the annoying notification.

gegoune commented 4 months ago

@WhyNotHugo Thank buddy! Your solution seems correct and works. Thank you very much for your time digging into this issue and coming up not only with solution but bunch of PRs as well improving ecosystem.

One thing I noticed is that having formatted buffer with vim.lsp.buf.format replaces entire .vue files' content with lines with single space. Filtering out tsserver fromvim.lsp.buf.format call fixes the issue. Just wanted to ask if you have experienced something like that as well? I am happy with prettier so can leave It disabled, but it feels bit odd (@johnsoncodehk perhaps an issue in @vue/typescript-plugin?).

And last but by far not least, @johnsoncodehk, thank you for all your work here too, especially during this busy times dealing with plethora of low quality issue reports, not to mention sometimes bit entitled in their nature too. You are doing community a massive favour and many silently appreciate it!

WhyNotHugo commented 4 months ago

Not sure about that, I already had formatting for tsserver disabled (it never yielded good results):

vim.api.nvim_create_autocmd('LspAttach', {
  callback = function(args)
    local client = vim.lsp.get_client_by_id(args.data.client_id)

    -- Ignore the formatting capabilities for these specific language servers.
    for _, name in ipairs({"lua_ls", "tsserver", "volar"}) do
      if client.name == name then
        return
      end
    end

    if client.server_capabilities.documentFormattingProvider then
      vim.keymap.set("n" , "<Leader>a", function()
        vim.lsp.buf.format({ async = true })
      end, { remap = true, desc = "Autoformat code (via LSP)" })
    end

    if client.server_capabilities.documentRangeFormattingProvider then
      vim.keymap.set( "v" , "<Leader>a", function()
        vim.lsp.formatexpr()
      end, { remap = true, desc = "Autoformat selected code (via LSP)" })
    end

  end,
})

I just used prettier via ALE.

gegoune commented 4 months ago

@WhyNotHugo Would you mind trying to remove it from filters just to see if you experience the same? Might just be my set up or actually a bug worth filing somewhere.

ogios commented 4 months ago

do you get autocompletion using Directives in SFC files? mine's didn't, only snippets.

image

creativenull commented 4 months ago

I'm a little bit confused with the new update to v2, it looks like all we need is typescript language server/tsserver for js/ts and vue file.

So is there no need for the vue-language-server for vue files anymore, if using outside of vscode?

jblyberg commented 4 months ago

For anyone wanting to get rid of the annoying no information notices, I added this filter and it works well.

local banned_messages = {
  "No information available"
}

vim.notify = function(msg, ...)
  for _, banned in ipairs(banned_messages) do
    if msg == banned then
      return
    end
  end
  require("notify")(msg, ...)
end
sid-6581 commented 4 months ago

I installed @vue/typescript-plugin together with tsserver, but it still won't yield error diagnostics for a SFC file.

I'm taking a pretty straightforward approach here:

  tsserver = {
    -- I installed @vue/typescript-plugin inside this container:
    cmd = lsp_containers.command("tsserver"),
    settings = {
      tsserver_plugins = {
        "@vue/typescript-plugin",
      },
    },
    filetypes = {
      "javascript",
      "typescript",
      "vue",
    },
  },

For regular typescript files, tsserver can't seem to resolve those SFC. E.g.: for line import Header from "./components/Header.vue";, it shows:

Cannot find module './components/Header.vue' or its corresponding type declarations.

Were you ever able to figure out the SFC import from a regular typescript file? I get a warning in vue-tsc. In neovim with volar/tsserver I don't get a warning (not sure why), but the import also doesn't show any details in the hover popup. The hover popup shows the details just fine for components imported in vue files.