Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Neovim #188

Closed
pBorak opened this issue Jul 7, 2022 · 37 comments
Closed

Support for Neovim #188

pBorak opened this issue Jul 7, 2022 · 37 comments

Comments

@pBorak
Copy link

pBorak commented Jul 7, 2022

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.

@vinistock
Copy link
Member

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?

@alexwu
Copy link

alexwu commented Jul 8, 2022

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!

@pBorak
Copy link
Author

pBorak commented Jul 8, 2022

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

@vinistock
Copy link
Member

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.

@alexwu
Copy link

alexwu commented Jul 8, 2022

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

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

@alexventuraio
Copy link

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

@wassimk
Copy link

wassimk commented Aug 16, 2022

@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

@vinistock
Copy link
Member

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.

@wassimk
Copy link

wassimk commented Aug 16, 2022

@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.

@alexventuraio
Copy link

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

@cj
Copy link

cj commented Sep 29, 2022

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

@wassimk
Copy link

wassimk commented Sep 30, 2022

@cj I believe diagnostics stopped working with the Neovim LSP client with this change #242.

@vinistock
Copy link
Member

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

@alexwu
Copy link

alexwu commented Sep 30, 2022

@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.

@jameswritescode
Copy link
Member

jameswritescode commented Oct 5, 2022

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

@technicalpickles
Copy link
Contributor

technicalpickles commented Nov 22, 2022

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
Copy link
Contributor

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
Copy link
Contributor

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 🤔

@mihyaeru21
Copy link

mihyaeru21 commented Jan 16, 2023

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

@technicalpickles
Copy link
Contributor

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 neovim/nvim-lspconfig#1886 and https://github.com/mihyaeru21/nvim-lspconfig-bundler . Confirmed the plugin runs through bundler 🎉

@arashm
Copy link

arashm commented Feb 25, 2023

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

@vinistock
Copy link
Member

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.

@smarquez1
Copy link

Link to related neovim and nvim-lspconfig issues:

@vinistock
Copy link
Member

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).

@b-sep
Copy link

b-sep commented Apr 29, 2023

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

@cefigueiredo
Copy link

@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

@b-sep
Copy link

b-sep commented Apr 30, 2023

@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 :)

@technicalpickles
Copy link
Contributor

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 #206

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

@vinistock
Copy link
Member

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.

@jameswritescode
Copy link
Member

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.

@technicalpickles
Copy link
Contributor

I stand corrected, thanks for the info! I'll need to look more closely how things behave when both ruby-lsp and sorbet are enabled to see if there is actually any duplicates.

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

Thanks for checking that out. I was in a interim stage while debugging some other LSP related things 😅

@technicalpickles
Copy link
Contributor

I posted this over on @cefigueiredo's neovim/nvim-lspconfig#2498 , but figured would share here too:

Would it be reasonable to just added the recommended workaround to lua/lspconfig/server_configurations/ruby_ls.lua rather than documenting the workaround? That way, users get a better out of box experience until there is support in neovim itself.

I can think of a few ways to detect the older versions, but they are kinda dirty. ruby-lsp doesn't have a --version flag unfortunately. It would be in someone's Gemfile.lock if they have it for their project, but that isn't always how it's installed.

Maybe an option to work for new vs old ruby-lsp?

I'm just trying to work out what the easiest way to enable vim folks to use ruby-lsp without needing much extra configuration. I think it's moving the workaround into nvim-lspconfig, or maybe another package?

Is there anything that can be implemented within ruby-lsp?

@metalelf0
Copy link

I'm trying to set ruby-lsp up in my neovim config. The gem is installed correctly and it seems to start fine. When I enter any ruby file, though, I get this error in the LspLog:

LSP[ruby_ls]: Error INVALID_SERVER_MESSAGE: {
  jsonrpc = "2.0"
}

I don't think I have anything fancy set up, just the usual nvim-lspconfig stuff + mason and diagnostics, but from the error it looks like neovim is not even "establishing a communication" with the LSP, right?

I tried searching online but I have literally no clue about where to start to address this issue.

Any clue about what I might be missing / doing wrong? My dot files are here:

https://github.com/metalelf0/dot-files/tree/master/.config/nvim

Thanks in advance!

@atishdhu
Copy link

Problem

I am using NvChad with the following lspconfig for ruby_ls.

lspconfig.ruby_ls.setup {
  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,
  capabilities = capabilities,
}

I added the workaround to make diagnostics work in neovim but there is an error when i make a change in a .rb file:

Error executing vim.schedule lua callback: /home/adhu/.config/nvim/lua/custom/configs/lspconfig.lua:67: attempt to index local 'result' (a nil value)

:LspInfo

image

@vinistock
Copy link
Member

Closing this since instructions were added in #830. If there are other instructions for different NeoVim plugins that can connect to the LSP, please feel free to put up a PR adding the configuration to a new section in that file.

@staycreativedesign
Copy link

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!

How would I lazy load this using return { } ?

andyw8 pushed a commit to andyw8/ruby-lsp that referenced this issue Mar 2, 2024
…ypescript-eslint/eslint-plugin-5.33.1

Bump @typescript-eslint/eslint-plugin from 5.33.0 to 5.33.1
@wassimk
Copy link

wassimk commented Jun 11, 2024

How would I lazy load this using return { } ?

I need help understanding the question. The LSP will only start in Ruby files. That should be the required lazy loading.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests