ruby-lsp icon indicating copy to clipboard operation
ruby-lsp copied to clipboard

Support for Neovim

Open pBorak opened this issue 2 years ago • 15 comments

Let me start by saying I am so excited that ruby tooling has gotten some love lately. Are there a plans to add support for other editors (most notably) Neovim? Neovim since version 0.5 natively supports Language Server Protocol and there is a significant subset of already supported LSP.

pBorak avatar Jul 07 '22 07:07 pBorak

Hey! Based on my understanding, we'd need to add a file similar to this one for the sorbet LSP, correct?

In terms of basic configuration, I believe all that'd be needed is

  • set the executable to bundle exec ruby-lsp
  • set the start event to be any directory with a Gemfile.lock or on Ruby files
  • send the enabled features list in the initialization options

Here is where we send the initializationOptions in VS Code. It's just an array of strings like

enabledFeatures: ["documentSymbols", "foldingRanges", ...]

And here are all of the feature names.

I'm not super familiar with Neovim. Could we test this out and make sure it works before contributing to nvim-lspconfigs?

vinistock avatar Jul 07 '22 13:07 vinistock

I just wanted to hop in and drop my neovim config that I've been using for a little while:

local lspconfig = require("lspconfig")
local configs = require("lspconfig.configs")
local util = require("lspconfig.util")

if not configs.ruby_lsp then
	local enabled_features = {
		"documentHighlights",
		"documentSymbols",
		"foldingRanges",
		"selectionRanges",
		-- "semanticHighlighting",
		"formatting",
		"codeActions",
	}

	configs.ruby_lsp = {
		default_config = {
			cmd = { "bundle", "exec", "ruby-lsp" },
			filetypes = { "ruby" },
			root_dir = util.root_pattern("Gemfile", ".git"),
			init_options = {
				enabledFeatures = enabled_features,
			},
			settings = {},
		},
		commands = {
			FormatRuby = {
				function()
					vim.lsp.buf.format({
						name = "ruby_lsp",
						async = true,
					})
				end,
				description = "Format using ruby-lsp",
			},
		},
	}
end

lspconfig.ruby_lsp.setup({ on_attach = on_attach, capabilities = capabilities })

I hope this helps!

alexwu avatar Jul 08 '22 17:07 alexwu

@alexwu Thanks! Isn't bundle exec required in the cmd tho?

pBorak avatar Jul 08 '22 17:07 pBorak

If you use it without bundler and your app has RuboCop extensions (e.g.: rubocop-performance), it will fail when trying to require them.

We are going to explore allowing the Ruby LSP to be executed without bundler, but then it'll probably fall back to formatting files using SyntaxTree and disable all RuboCop functionality.

vinistock avatar Jul 08 '22 19:07 vinistock

@alexwu Thanks! Isn't bundle exec required in the cmd tho?

Nice catch -- I've updated the snippet it to use bundler.

alexwu avatar Jul 08 '22 20:07 alexwu

To try this, I just need to install the ruby-lsp gem and where should I put @alexwu config?

alexventuraio avatar Aug 15 '22 16:08 alexventuraio

@alexventuraio, after you install ruby-lsp via your Gemfile and the nvim-lspconfig plugin, you can put @alexwu instruction anywhere in your Vim configuration. You'll probably want to create some keymaps for jumping around. Look at the nvim-lspconfig README for a good starting setup.

If your vim configuration is not in Lua, then you insert Lua code with:

lua <<EOF
print('hello from lua')
EOF

wassimk avatar Aug 16 '22 13:08 wassimk

While our team's focus is on supporting VS Code, we'd gladly add an EDITOR_SETUP.md file linked from the README with community driven instructions on how to get the Ruby LSP working on other editors.

Would that be helpful? We could get started with neovim.

vinistock avatar Aug 16 '22 13:08 vinistock

@vinistock yes, I think that would be helpful. I have a branch adding ruby-lsp to the nvim-lspconfig project. Once that goes through I'll be happy to write some Neovim instructions.

wassimk avatar Aug 16 '22 14:08 wassimk

@wassimk thanks for sharing your solution, I'm looking forward to go through your PR and read your instructions to get it done.

alexventuraio avatar Aug 16 '22 22:08 alexventuraio

@alexwu thank you for your config, it worked great. I did notice one issue, diagnostics errors do not show.

cj avatar Sep 29 '22 21:09 cj

@cj I believe diagnostics stopped working with the Neovim LSP client with this change https://github.com/Shopify/ruby-lsp/pull/242.

wassimk avatar Sep 30 '22 16:09 wassimk

Does the Neovim LSP support the specification version 3.17? It should work if it does.

vinistock avatar Sep 30 '22 19:09 vinistock

@cj @wassimk Darn, I've been a bit behind on ruby-lsp versions of late, so I didn't know about this.

I'll see if there's any info on neovim supporting that spec when I get the chance.

alexwu avatar Sep 30 '22 21:09 alexwu

neovim does not support textDocument/diagnostic with no official plans to support it

from matrix:

   newton | are there any plans to support textDocument/diagnostic to request diagnostics from LSP?
gpanders_ | no current plans, but that does not mean a PR implementing that support would be rejected

here's a snippet nvim lsp users can incorporate into their configs to request textDocument/diagnostic regularly:

on_attach = function(client, bufnr)
  vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePre', 'CursorHold' }, {
    buffer = bufnr,

    callback = function()
      local params = vim.lsp.util.make_text_document_params(bufnr)

      client.request(
        'textDocument/diagnostic',
        { textDocument = params },
        function(err, result)
          if err then return end
          if not result then return end

          vim.lsp.diagnostic.on_publish_diagnostics(
            nil,
            vim.tbl_extend('keep', params, { diagnostics = result.items }),
            { client_id = client.id }
          )
        end
      )
    end,
  })
end

jameswritescode avatar Oct 05 '22 20:10 jameswritescode

It looks like lspconfig now ships with support directly: https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#ruby_ls

The only thing you may need to change the cmd to use bundler, ie:

local lspconfig = require("lspconfig")

lspconfig.ruby_ls.setup({
	cmd = { "bundle", "exec", "ruby-lsp" }
})

edit added a note about what you may need to change

technicalpickles avatar Nov 22 '22 18:11 technicalpickles

here's a snippet nvim lsp users can incorporate into their configs to request textDocument/diagnostic regularly

I have tried this snippet, and one problem I'm seeing is that you don't get diagnostics when I first load a file. I have to make a change and save. I tried addding like BufRead or BufReadPre, but had same results (I'm not super familiar with autocmd stuff)

technicalpickles avatar Nov 23 '22 14:11 technicalpickles

One downside I'm seeing for using the lsp is that you'll see an error about connecting to the LSP when the Gemfile doesn't have it. I'm not sure if there's a way to have a callback to determine that 🤔

technicalpickles avatar Dec 02 '22 16:12 technicalpickles

I have tried this snippet, and one problem I'm seeing is that you don't get diagnostics when I first load a file. I have to make a change and save. I tried addding like BufRead or BufReadPre, but had same results (I'm not super familiar with autocmd stuff)

This worked fine for me.

on_attach = function(client, buffer)
  local callback = function()
    local params = vim.lsp.util.make_text_document_params(buffer)

    client.request(
      'textDocument/diagnostic',
      { textDocument = params },
      function(err, result)
        if err then return end

        vim.lsp.diagnostic.on_publish_diagnostics(
          nil,
          vim.tbl_extend('keep', params, { diagnostics = result.items }),
          { client_id = client.id }
        )
      end
    )
  end

  callback() -- call on attach

  vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePre', 'BufReadPost', 'InsertLeave', 'TextChanged' }, {
    buffer = buffer,
    callback = callback,
  })
end

mihyaeru21 avatar Jan 16 '23 17:01 mihyaeru21

One downside I'm seeing for using the lsp is that you'll see an error about connecting to the LSP when the Gemfile doesn't have it. I'm not sure if there's a way to have a callback to determine that

I found a way to do this 🎉 I was looking at adding on_new_config, but in looking for options I came across https://github.com/neovim/nvim-lspconfig/issues/1886 and https://github.com/mihyaeru21/nvim-lspconfig-bundler . Confirmed the plugin runs through bundler 🎉

technicalpickles avatar Feb 15 '23 15:02 technicalpickles

coc.nvim also kinda supports it https://github.com/neoclide/coc.nvim/wiki/Language-servers#using-shopifyruby-lsp

arashm avatar Feb 25 '23 19:02 arashm

Folks, I added an editors file to aggregate configurations for the Ruby LSP in editors other than VS Code. If somebody wants to contribute instructions for NeoVim, we can put it there and close this issue.

We can also include multiple alternatives if there's not a single way of doing it.

vinistock avatar Mar 06 '23 20:03 vinistock

Link to related neovim and nvim-lspconfig issues:

  • https://github.com/neovim/nvim-lspconfig/pull/2498
  • https://github.com/neovim/neovim/issues/22838

smarquez1 avatar Mar 31 '23 15:03 smarquez1

Another thing that might help: since #562, we switched features from being opt-in to being opt-out so that configuration is easier for editors (everything is enabled by default if no config is passed).

vinistock avatar Mar 31 '23 15:03 vinistock

any help?

lsp_config.lua

local status_ok, lspconfig = pcall(require, 'lspconfig')
if not status_ok then
  return
end

local servers = require("junior.lsp.servers")

for _, server in pairs(servers) do
  local opts = {}
  local handler = require("junior.lsp.handlers")

  opts = {
    on_attach = handler.on_attach,
    capabilities = handler.capabilities,
  }

  if server == 'lua_ls' then
    opts = vim.tbl_deep_extend("force", {
      settings = {
        Lua = {
          diagnostics = {
            globals = { "vim" },
          },
        },
      },
    }, opts)
  end

  lspconfig[server].setup(opts)
end

servers.lua

local servers = {
  'lua_ls',
  'tsserver',
  'ruby_ls'
}

return servers

When i open a buffer with ruby file, i can see the the ruby_ls has attached to the buffer but i dont get any completion or diagnostic. I already tried the suggestions on this issue and nothing happens. Im have the gem installed btw.

image

on the LspLog i have this [ERROR] but i dont know what this means

image

b-sep avatar Apr 29 '23 18:04 b-sep

@b-sep We can not see the handler where you customize the on-attach. But probably it's missing the workaround to make neovim send diagnostic requests to ruby-lsp as suggested on a prior comment, and detailed here neovim/nvim-lspconfig#2498

cefigueiredo avatar Apr 30 '23 05:04 cefigueiredo

@b-sep We can not see the handler where you customize the on-attach. But probably it's missing the workaround to make neovim send diagnostic requests to ruby-lsp as suggested on a prior comment, and detailed here neovim/nvim-lspconfig#2498

my handlers file is just a bunch of mappings and visual stuff, you can see here

i'll try the workaround that u link, ty :)

b-sep avatar Apr 30 '23 15:04 b-sep

I'm not sure if this is neovim specific, or a broader ruby-lsp question: if you use sorbet, is there any guidance/recommendations for using the sorbet LSP and ruby-lsp together? There is definitely some overlap as noted in https://github.com/Shopify/ruby-lsp/issues/206

I'm still learning and understanding nvim + lsp, but I get the impression only one ruby LSP ends up being attached.

technicalpickles avatar May 03 '23 13:05 technicalpickles

The default behaviour for language servers is to allow for more than one and merge responses. If both the Ruby LSP and Sorbet implement the same request, you'd just get the results duplicated in the editor.

We use both Sorbet and the Ruby LSP on our projects (even on the Ruby LSP project itself, we use both). This works out of the box on VS Code, but I have no idea how NeoVim handles it.

vinistock avatar May 03 '23 13:05 vinistock

The default behaviour for language servers is to allow for more than one and merge responses. If both the Ruby LSP and Sorbet implement the same request, you'd just get the results duplicated in the editor.

This is also my experience using both together.

I'm still learning and understanding nvim + lsp, but I get the impression only one ruby LSP ends up being attached.

@technicalpickles Looking at your committed configuration here sorbet is autostart = false so unless you are manually starting it later I assume it wouldn't attach.

jameswritescode avatar May 03 '23 18:05 jameswritescode