nvim-lspconfig icon indicating copy to clipboard operation
nvim-lspconfig copied to clipboard

LSP features not working in second dotnet solution with OmniSharp

Open starteleport opened this issue 2 years ago • 5 comments

Description

I'm not sure if it's lspconfig-related or omnisharp-related, so posting it here to start with.

Neovim version

NVIM v0.9.0-dev-774+g151b9fc52-dirty Build type: Release LuaJIT 2.1.0-beta3

Nvim-lspconfig version

85cd2ecacd8805614efe3fb3a5146ac7d0f88a17

Operating system and version

macOs 13.1

Affected language servers

omnisharp

Steps to reproduce

Step 1: open file from solution 1

LspInfo:

 Language client log: /Users/starteleport/.local/state/nvim/lsp.log
 Detected filetype:   cs
 
 1 client(s) attached to this buffer: 
 
 Client: omnisharp (id: 1, bufnr: [1])
 	filetypes:       cs, vb
 	autostart:       true
 	root directory:  /Users/starteleport/my_code/solution1
 	cmd:             omnisharp -z -s /Users/starteleport/my_code/solution1 --hostPID 59024 DotNet:enablePackageRestore=false --encoding utf-8 --languageserver FormattingOptions:EnableEditorConfigSupport=true Sdk:IncludePrereleases=true
 
 Configured servers list: omnisharp

Step 2: check whether things like goto definition work within solution 1

Step 3: open file from solution 2

LspInfo:

 Language client log: /Users/starteleport/.local/state/nvim/lsp.log
 Detected filetype:   cs
 
 1 client(s) attached to this buffer: 
 
 Client: omnisharp (id: 1, bufnr: [1, 7])
 	filetypes:       cs, vb
 	autostart:       true
 	root directory:  /Users/starteleport/my_code/solution2
 	cmd:             omnisharp -z -s /Users/starteleport/my_code/solution1 --hostPID 59024 DotNet:enablePackageRestore=false --encoding utf-8 --languageserver FormattingOptions:EnableEditorConfigSupport=true Sdk:IncludePrereleases=true -z -s /Users/starteleport/my_code/solution2 --hostPID 59024 DotNet:enablePackageRestore=false --encoding utf-8 --languageserver FormattingOptions:EnableEditorConfigSupport=true Sdk:IncludePrereleases=true
 
 Configured servers list: omnisharp

Step 4: check whether things like goto definition work within solution 2

Step 5: issue ps -A to verify how many instances of omnisharp are started and with which parameters

Actual behavior

Goto definition from step 2 work within solution 1.

Goto definition from step 4 do not work within solution 2.

LspInfo in step 4 show suspicious cmd value that expands even further as I open subsequent buffers.

cmd value in step 4 does not match the output from ps -A in step 5

Expected behavior

Goto definition from step 2 work within solution 1.

Goto definition from step 4 work within solution 2.

LspInfo in step 4 shows adequate cmd value that matches the output of ps -A.

Minimal config

local on_windows = vim.loop.os_uname().version:match 'Windows'

local function join_paths(...)
  local path_sep = on_windows and '\\' or '/'
  local result = table.concat({ ... }, path_sep)
  return result
end

vim.cmd [[set runtimepath=$VIMRUNTIME]]

local temp_dir = vim.loop.os_getenv 'TEMP' or '/tmp'

vim.cmd('set packpath=' .. join_paths(temp_dir, 'nvim', 'site'))

local package_root = join_paths(temp_dir, 'nvim', 'site', 'pack')
local lspconfig_path = join_paths(package_root, 'test', 'start', 'nvim-lspconfig')

if vim.fn.isdirectory(lspconfig_path) ~= 1 then
  vim.fn.system { 'git', 'clone', 'https://github.com/neovim/nvim-lspconfig', lspconfig_path }
end

vim.lsp.set_log_level 'trace'
require('vim.lsp.log').set_format_func(vim.inspect)
local nvim_lsp = require 'lspconfig'
local on_attach = function(_, bufnr)
  local function buf_set_option(...)
    vim.api.nvim_buf_set_option(bufnr, ...)
  end

  buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')

  -- Mappings.
  local opts = { buffer = bufnr, noremap = true, silent = true }
  vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, opts)
  vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts)
  vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts)
  vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, opts)
  vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, opts)
  vim.keymap.set('n', '<space>wa', vim.lsp.buf.add_workspace_folder, opts)
  vim.keymap.set('n', '<space>wr', vim.lsp.buf.remove_workspace_folder, opts)
  vim.keymap.set('n', '<space>wl', function()
    print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
  end, opts)
  vim.keymap.set('n', '<space>D', vim.lsp.buf.type_definition, opts)
  vim.keymap.set('n', '<space>rn', vim.lsp.buf.rename, opts)
  vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts)
  vim.keymap.set('n', '<space>e', vim.diagnostic.open_float, opts)
  vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts)
  vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts)
  vim.keymap.set('n', '<space>q', vim.diagnostic.setloclist, opts)
end

-- Add the server that troubles you here
local name = 'omnisharp'
local cmd = { 'omnisharp' } -- needed for elixirls, omnisharp, sumneko_lua
if not name then
  print 'You have not defined a server name, please edit minimal_init.lua'
end
if not nvim_lsp[name].document_config.default_config.cmd and not cmd then
  print [[You have not defined a server default cmd for a server
    that requires it please edit minimal_init.lua]]
end

nvim_lsp[name].setup {
  cmd = cmd,
  on_attach = on_attach,
}

print [[You can find your log at $HOME/.cache/nvim/lsp.log. Please paste in a github issue under a details tag as described in the issue template.]]

LSP log

https://gist.github.com/starteleport/055fedceaea9e2ef22dd2ff9e6be43d9

starteleport avatar Jan 11 '23 11:01 starteleport

to be honest I don't find the textDocument/definition request in your log.

glepnir avatar Jan 15 '23 10:01 glepnir

Sorry, wrong log file. I've updated the gist as well as NeoVim/lspconfig revisions in bug description (just updated everything to the latest masters).

starteleport avatar Jan 22 '23 17:01 starteleport

I believe I figured out part of the problem. The on_new_config function for omnisharp inserts the extra configurations to the cmd table. The issue with this is that it doesn't seem like the cmd table is ever cleared or recreated. This is what causing the repeating config options at the end of the command.

This section gets repeated many times. I've noticed on Windows this happens as soon as I open one solution -z -s /Users/starteleport/my_code/solution1 --hostPID 59024 DotNet:enablePackageRestore=false --encoding utf-8 --languageserver FormattingOptions:EnableEditorConfigSupport=true Sdk:IncludePrereleases=true

I created a temporary solution that works for my use case here. I'm just setting the new_config.cmd to a completely new table and setting the omnisharp dll elsewhere. Someone would have to come up with a proper solution.

I'm open to helping out when I can

waynebowie99 avatar Feb 02 '23 15:02 waynebowie99

@glepnir, were you able to reproduce this? Can I help here somehow?

starteleport avatar Mar 27 '23 07:03 starteleport

sry a little busy recently . I don't write dotnet. so need some time to install env and try to reproduce it.

glepnir avatar Mar 27 '23 08:03 glepnir

@waynebowie99 You've certainly identified the problem! I've spent countless hours and have come across multiple Issues (the GitHub kind) in other repos that have been opened—and subsequently closed—that were ultimately the fault of this bug.

Shoot, I've spend dozens of hours just trying to learn Lua in hopes of troubleshooting this. I think this is what's preventing me from using Hoffs/omnisharp-extended-lsp.nvim in my LazyVim configuration.

Does anybody more experienced than me have some time to work on this?

JustALawnGnome7 avatar Jun 19 '23 22:06 JustALawnGnome7

@glepnir As I'm looking over the code @waynebowie99 shared back on Feb 2, it seems he's on the right track by resetting new_config.cmd (i.e. setting the arguments to omnisharp from scratch). If this is indeed the right approach, how do we do this so that lspconfig's default path to omnisharp is used in subsequent command line resets—so that @waynebowie99's dll_path field is unnecessary?

Second, is it even correct for us to be trying to set new_config.cmd in most cases? In your professional opinion, is it a problem that on_new_config is being called every time we open a *.cs file under the same directory as the other files we have open?

JustALawnGnome7 avatar Jun 20 '23 17:06 JustALawnGnome7

This issue #2018 was the one that caused this breaking change. Maybe @williamboman has some insight on this and how to fix the problem

Thanks @JustALawnGnome7 for continuing this work on this!

waynebowie99 avatar Jun 23 '23 16:06 waynebowie99

I've submitted a PR that updates the logic behind on_new_config. The change saves the value of cmd—or rather its first parameter's cmd field—to be used in subsequent calls to on_new_config instead of appending duplicate arguments to cmd whenever another *.cs source file is opened.

It should be noted, however, that this still doesn't cause OmniSharp to work with multiple projects at the same time.

JustALawnGnome7 avatar Jun 27 '23 18:06 JustALawnGnome7

Whoops, looks like I botched the commit messages and created quite a mess. I've re-submitted the change under a new PR. (https://github.com/neovim/nvim-lspconfig/pull/2692)

JustALawnGnome7 avatar Jun 27 '23 19:06 JustALawnGnome7

So this required some extensive debugging. There seems to be two problems here:

  1. I had so far been under the impression that each client configuration table gets "deep copied" before use. This is not the case, it only creates a shallow copy of the table, so if you mutate a table field directly (such as table.insert(new_config.cmd, "something")) it'll mutate the shared config table. This is easily fixable (I've suggested an easier approach in #2692). Some other server configurations seem to suffer the same issue, I'll probably open a separate PR to fix these.

  2. The Omnisharp server does not seem to handle multiple workspaces per server instance (see https://github.com/OmniSharp/omnisharp-roslyn/issues/909 and other linked issues from VSCode users). For some reason the server seems to announce that it supports this capability, which causes lspconfig to attach a new workspace to an existing client. Any new opened workspace will effectively be unusable due to this. The following autocmd should patch the server capabilities to avoid this happening (note that I've also included a reset of semanticTokensProvider because of https://github.com/OmniSharp/omnisharp-roslyn/issues/2483):

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

        if client.name == "omnisharp" then
            client.server_capabilities.semanticTokensProvider = nil
            client.server_capabilities.workspace.workspaceFolders.supported = false
        end
    end,
})

-- (the better way would probably be to try to configure this via client capabilities, but I haven't given that a try yet)

The above could potentially also be somehow included directly in nvim-lspconfig for a better out-of-the-box experience.

williamboman avatar Jun 27 '23 19:06 williamboman