omnisharp-roslyn
omnisharp-roslyn copied to clipboard
Imports not detected when client sends only `textDocument/didOpen` on newly created file (Unity project, neovim client)
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
?
Having the same issue in Helix.
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.
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.
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.
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.
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.
![](https://user-images.githubusercontent.com/24765272/155379362-85466a59-d04b-423d-83ce-8899cc160a75.png)
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.
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.
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.
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.
That's great to hear! Is this change on the repo yet?
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
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?
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 ?
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).
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 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.
@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](https://user-images.githubusercontent.com/79347623/217965428-1e5b8d4f-6007-4a1e-a4be-e82d3f8581a0.png)
@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
@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 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 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
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...
@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 thank you!
and sorry for bothering...
@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.)
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)
@nyngwang How would one use this new feature to solve the new file issue?
@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.
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
(Neovimnews.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()`
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