ruby-lsp
ruby-lsp copied to clipboard
Support for Neovim
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.
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?
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 Thanks! Isn't bundle exec required in the cmd tho?
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 Thanks! Isn't bundle exec required in the cmd tho?
Nice catch -- I've updated the snippet it to use bundler.
To try this, I just need to install the ruby-lsp
gem and where should I put @alexwu config?
@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
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 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 thanks for sharing your solution, I'm looking forward to go through your PR and read your instructions to get it done.
@alexwu thank you for your config, it worked great. I did notice one issue, diagnostics errors do not show.
@cj I believe diagnostics stopped working with the Neovim LSP client with this change https://github.com/Shopify/ruby-lsp/pull/242.
Does the Neovim LSP support the specification version 3.17? It should work if it does.
@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.
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
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
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)
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 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
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 🎉
coc.nvim also kinda supports it https://github.com/neoclide/coc.nvim/wiki/Language-servers#using-shopifyruby-lsp
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.
Link to related neovim and nvim-lspconfig issues:
- https://github.com/neovim/nvim-lspconfig/pull/2498
- https://github.com/neovim/neovim/issues/22838
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).
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.
on the LspLog i have this [ERROR] but i dont know what this means
@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 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 :)
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.
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.
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.