omnisharp-roslyn icon indicating copy to clipboard operation
omnisharp-roslyn copied to clipboard

Imports not detected when client sends only `textDocument/didOpen` on newly created file (Unity project, neovim client)

Open mjlbach opened this issue 2 years ago • 30 comments

Hi!

I'm trying to troubleshoot some issues the client I work on has with omnisharp-roslyn, and I was hoping I could ping you all for help.

The issue is, when opening a unity project, say one containing the following file:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

Everything is fine, our client detects the imports no problem.

However, the minute we open a new file (for which we send the requisite textDocument/didOpen notification) with the exact same content, in the exact same subdirectory, the server returns import error messages:

The type or namespace name 'UnityEngine' could not be found (are you missing a using directive or an assembly reference?) irective or an assembly reference?)

Other servers seem to be fine recognizing new files this way. Do we need to send an additional notification when creating a new file such as workspace/didChangeWatchedFiles?

mjlbach avatar Oct 19 '21 04:10 mjlbach

Having the same issue in Helix.

ChimpSpin avatar Jan 19 '22 03:01 ChimpSpin

Unity projects are Full Framework style projects and require each code file to have a corresponding <Compile Include="{filename}" /> element in the .csproj to be included in the project. If you have added a new file without adding the <Compile> element, then I would expect O# to open the file in its "Miscellaneous" project which does not include any Unity dependencies.

Edit: After reviewing what happens when the FileChangeWatcher fires, there is a heuristic in O# that will match a new code file to an existing project based on whether the code file exists alongside or beneath the project file on the filesystem. This matching would not persist between sessions unless the project file was updated with the appropriate <Compile> element.

JoeRobich avatar Jan 25 '22 17:01 JoeRobich

However, the minute we open a new file

Is this a new file that has been saved and exists on disk?

Do we need to send an additional notification when creating a new file such as workspace/didChangeWatchedFiles?

If the file was added to the filesystem, then I expect that file watchers would need to be updated.

JoeRobich avatar Jan 25 '22 17:01 JoeRobich

Is this a new file that has been saved and exists on disk?

It's a new file that has not been added to the project. If I'm understanding you correctly then you must regenerate the solution files after the addition of a new file for omnisharp to pick up the imports correctly?

It seems to work fine in vscode creating a new file without regenerating the solution file in unity, no errors are thrown (left). Opening the same file in neovim (right) yields a bunch of errors.

image

Edit: After reviewing what happens when the FileChangeWatcher fires, there is a heuristic in O# that will match a new code file to an existing project based on whether the code file exists alongside or beneath the project file on the filesystem. This matching would not persist between sessions unless the project file was updated with the appropriate <Compile> element.

Is it possible that vscode is doing something on each startup that adds this file?

It seems like, on further glance, that vscode is not providing completion candidates (or hover) for UnityEngine on the newly added file without regenerating the solution file.

mjlbach avatar Jan 25 '22 20:01 mjlbach

Any progress now? This also happens after renaming of class. I have to click the button on External Tools > "Regenerate project files" to make MonoBehaviour detected by the LSP.

nyngwang avatar Feb 23 '22 17:02 nyngwang

I actually was able to maintain a sustainable workflow by creating a second class (let's say Foo.cs) on a already "Synced File" (where the LSP features work normally) and using the Code Action Move type to Foo.cs. That way it's possible to work on Foo.cs without problems. But that's just a workaround, but maybe it can lead us somewhere.

niscolas avatar Apr 15 '22 15:04 niscolas

A workaround I have found is to add the following line to Assembly-CSharp.csproj: <Compile Include="**/*.cs" />

As mentioned above, each Unity code file needs to have <Compile..../> element in the .csproj file. On neovim (using OmniSharp Roslyn LSP server), it seems like the .csproj file (specifically Assembly-CSharp.csproj) does not get automatically "refreshed" after it changes. The changes to .csproj file only seem to be applied after restarting neovim (and omnisharp). This doesn't seem to be the case with vscode, however. When making changes to .csproj file (adding the compile element), vscode directly picks up the change and omnisharp server seems to be working as intended.

I believe "Regenerate Project Files" button on Unity just ensures there's the <Compile.../> tag in the .csproj file for newly created/renamed files. There is a Unity plugin for vscode (and a modified version to work with neovim) that automatically regenerates the project files when there's a new file. This is done in Unity though.

I doubt my workaround is going to be a good solution in the long run, mostly because Unity generates this file, which will override the line I've described above.

crissNb avatar Oct 14 '22 18:10 crissNb

I'll test that approach later. But what I've found is it seems like there're 2 different problems. There're some repos on GitHub mimicking the behavior of Unity plugins for VSCode and JetBrains Rider, like this: https://github.com/neovim/neovim/issues/17808#issue-1175601347 I even tried to improve on it myself, but even using Unity's API to Regenerate Project Files automatically on file changed, the behavior described in this issue still occurs.

niscolas avatar Oct 14 '22 20:10 niscolas

I've been looking into this in a similar issue for OmniSharp-vim. From what I've seen, I believe omnisharp-vscode has a file watcher watching the .csproj file, and when it is modified (by Unity, which adds a new <Compile ...> element for the new file) then vscode sends a /filesChanged request for the csproj to OmniSharp-roslyn, which then reloads the project.

I've tried to mimic this /filesChanged request from OmniSharp-vim and works - the new file is now part of the project, without requiring a full OmniSharp-roslyn restart.

nickspoons avatar Oct 14 '22 20:10 nickspoons

That's great to hear! Is this change on the repo yet?

niscolas avatar Oct 14 '22 20:10 niscolas

Which repo? OmniSharp-vim? Not yet. But I'm just adding it as a command, :OmniSharpRelosdProject, there aren't file watchers in OmniSharp-vim.

I was letting you know what my findings were in case you wanted to investigate making that /filesChanged request from neovim lsp

nickspoons avatar Oct 14 '22 20:10 nickspoons

Oh... 1 issue may be that OmniSharp-vim doesn't run OmniSharp-roslyn on LSP mode. I'm not sure if omnisharp-vscode has switched to LSP mode either? So I don't know if the /filesChanged endpoint will have the same effect from neovim LSP. Hopefully?

nickspoons avatar Oct 14 '22 20:10 nickspoons

is it possible to watch the files from nvim and send request when the document is changed and document created

for unity i notice the .csproj file is changing after adding, removing and renaming files. is it possible to watch this .csproj file ?

if it possible did the request to server reload all the index ?

gsihaj5 avatar Oct 27 '22 04:10 gsihaj5

Is there any update to this issue? Adding on to what has been previously said: From my testing, although I'm not entirely certain, I've noticed that making changes (i.e. adding a new line of <Compile> tag) to the .csproj does not queue the project file for ProjectManager to process. Is this an expected behavior from file watchers?

Another combination I've tested is adding the <Compile> tag before adding the .cs file itself in a same session. This also didn't work, as .csproj did not get queued (according to my assumption).

crissNb avatar Nov 19 '22 11:11 crissNb

Following the idea from @nickspoons above (with my little knowledge of LSPs) I tried to find if there's a way to make a similar request to this /filesChanged in to the Omnisharp LSP client. Unfortunately, it seems that this endpoint doesn't exist for the LSP side. These are the endpoints for Omnisharp, it's listed on the "v1", but I think these endpoints are only really valid for non LSP stuff, these are the handlers for the LSP part The closest I could find was this: OmnisharpOnDidChangeWatchedFilesHandler But doesn't seem that there's a way to request something from it, and I don't really know how to interact with it. Sorry for the dumbness but I don't really know much about LSP, just leaving my little research.

niscolas avatar Dec 22 '22 21:12 niscolas

@niscolas I finally found something related: https://github.com/neovim/neovim/pull/21293, which is a PR that could be an important factor in finding/creating the solution to the problem.

nyngwang avatar Feb 01 '23 04:02 nyngwang

@ChimpSpin have you managed to get it working on helix? I see that some people above (https://github.com/OmniSharp/omnisharp-roslyn/issues/2250#issuecomment-1049056993) have vscode as their configured editor, and it seems it generates some files (seemingly config files) that may be involved in allowing the lsp to work correctly.

As a note, I don't even have basic functionality for a single file... so I would really thank you, if you could help me :)

Screenshot 2023-02-09 at 5 56 16 p m

0rphee avatar Feb 09 '23 23:02 0rphee

@0rphee
I think that for being able to work without major issues with Unity (except the one discussed in this issue), you need:

  • A properly working Neovim + LSP setup
  • Have the Omnisharp LSP server installed and configured (I recommend Mason for that)
  • Have a secondary editor directly supported by Unity and with an official integration plugin (either Visual Studio or Jetbrains Rider, since Unity seems to be dropping support for VSCode - link) That's what I've always done and had no problems besides this one

niscolas avatar Feb 10 '23 00:02 niscolas

@nyngwang

@niscolas I finally found something related: neovim/neovim#21293, which is a PR that could be an important factor in finding/creating the solution to the problem.

That's super interesting! That seems to indeed solve the issue here, have you tested the solution on that PR?

niscolas avatar Feb 10 '23 00:02 niscolas

@niscolas thanks, though I forgot to mention that I don't use nvim! I use helix... anyway, maybe I will take a look at the links that you talk about. They may help, thanks!

0rphee avatar Feb 10 '23 00:02 0rphee

@0rphee I had to download https://github.com/OmniSharp/omnisharp-roslyn and add this to my languages.toml

[[language]]
name = "c-sharp"
language-server = { command = "<Your path to>/OmniSharp.exe", args = ["--languageserver" ] }

ChimpSpin avatar Feb 14 '23 00:02 ChimpSpin

@ChimpSpin I already have that in my languages.toml, but omnisharp doesnt seem to find UnityEngine as shown in the image from my first comment (https://github.com/OmniSharp/omnisharp-roslyn/issues/2250#issuecomment-1424992708). Did you have to change any other settings specifically to get it working with Unity?

sorry for bothering :( its just that I am a bit lost with this...

Screenshot 2023-02-09 at 5 56 16 p m

0rphee avatar Feb 14 '23 03:02 0rphee

@0rphee Aside from that, I just had to generate the project files from within unity.

Edit > Preferences > External Tools > Regenerate project files

I don't think there was anything else to it.

ChimpSpin avatar Feb 14 '23 16:02 ChimpSpin

@ChimpSpin thank you!

and sorry for bothering...

0rphee avatar Feb 14 '23 20:02 0rphee

@niscolas FYI: The linked PR I mentioned 3 weeks ago had been merged into Neovim recently: https://github.com/neovim/neovim/pull/21293. (Haven't tested it though, but definitely usable for Nvim-Unity plugin author.)

nyngwang avatar Mar 06 '23 20:03 nyngwang

Yay, that's great! I'll be taking a look as soon as I can to check whether it solves the issue and if we will still need some kind of plugin in either side (Neovim / Unity)

niscolas avatar Mar 06 '23 23:03 niscolas

@nyngwang How would one use this new feature to solve the new file issue?

steventhorne avatar Mar 31 '23 20:03 steventhorne

@nyngwang How would one use this new feature to solve the new file issue?

Bump, I also wanna know. Kinda a newb in all this.

dimixar avatar Apr 06 '23 20:04 dimixar

I believe that I just got it to work.

  • You should be using a build for Neovim that includes the changes in the PR above (link), I recommend just using bob to install Neovim nightly
  • Your LSP Capabilities table should include workspace.didChangeWatchedFiles.dynamicRegistration = true (Neovim news.txt), example:
local cmp_nvim_lsp = require("cmp_nvim_lsp")
local capabilities = cmp_nvim_lsp.default_capabilities()
capabilities = vim.tbl_deep_extend("force", capabilities, {
    workspace = {
        didChangeWatchedFiles = {
            dynamicRegistration = true,
        },
    },
})
// pass `capabilities` to your LSP server `setup()`

niscolas avatar Apr 06 '23 22:04 niscolas

I only tested this by creating the file through Unity, so I think it automatically adds the file to the Assembly-CSharp.csproj. If creating files directly from Neovim, there's the need of using a package in the Unity side, like this one: https://github.com/niscolas/com.unity.ide.neovim-fork I didn't test it recently, but it should work, it also adds Neovim as an External Editor option in Unity's settings

niscolas avatar Apr 06 '23 23:04 niscolas