Open bitinn opened 6 years ago
Thanks for reporting this @bitinn. Looks like this issue was fixed on Windows but still happens on OS X. We'll take a look.
@bitinn I'm having trouble reproducing this on my Mac. Do you see this issue in a simple project (eg, dotnet new console
and add a file), or only in your large project?
For this feature to work, your project needs to have file globbing enabled within the csproj files. Otherwise, when you add a file, omnisharp doesn't know what project to associate it with.
@rchande Just a large Unity project it seems, I tried a separate project where I build a small plugin (dll) for Unity and the issue doesn't appear when I add a new file.
I think the problem here is that Unity projects do not support file globbing and C# for VS Code does not automatically update your project file to add/change/remove <Compile Include="your_new_file.cs" />
s for new or renamed files. It looks to me like this is the same as https://github.com/OmniSharp/omnisharp-vscode/issues/1970.
@DustinCampbell since this is a known limit, are there:
Basically, using VS Code with Unity means VS Code don't have to "build" the project. I just need it to know enough about Unity and my source code so that OmniSharp can provide basic intellisense suggestions.
You should be able to restart OmniSharp as a workaround. Run OmniSharp: Restart OmniSharp
from the VS Code command palette.
You could use globbing patterns in your file. MSBuild supports them. Unfortunately, Unity does not. Unity will just stomp over your globs the next time it generates your project.
Basically, using VS Code with Unity means VS Code don't have to "build" the project. I just need it to know enough about Unity and my source code so that OmniSharp can provide basic intellisense suggestions.
Note that getting IntelliSense means performing a "build". This is design-time build that does not actually compile binaries. However, from the MSBuild perspective, it is still a build in that references need to be resolved, conditions in the project file must be evaluated, etc.
@DustinCampbell thx for that!
But one more question: I don't fully understand why OmniSharp needs <Compile Include="your_new_file.cs" />
to see new file: for my smaller project, it appears my .csproj file only include existing files anyway, so how did OmniSharp discover a new file?
(In below example, only BLogger.cs is in the csproj file, I added a DLogger.cs and OmniSharp is able to discover it without refresh.)
EDIT: I am not sure if #1970 only concerns rename (which means .csproj points to a file that no longer exists) or does it include creating new file (which means .csproj doesn't include such a file). It might be the same either way, but then I don't understand how OmniSharp is able to discover new file for my smaller project (which was created from VS Community, but I don't see a file glob pattern?)
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BeginHQ.Plugins", "BeginHQ.Plugins\BeginHQ.Plugins.csproj", "{AA98C067-30E5-4D1B-8F2D-71BE4B36D4CE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AA98C067-30E5-4D1B-8F2D-71BE4B36D4CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AA98C067-30E5-4D1B-8F2D-71BE4B36D4CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA98C067-30E5-4D1B-8F2D-71BE4B36D4CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA98C067-30E5-4D1B-8F2D-71BE4B36D4CE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{AA98C067-30E5-4D1B-8F2D-71BE4B36D4CE}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>BeginHQ.Plugins</RootNamespace>
<AssemblyName>BeginHQ.Plugins</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="UnityEditor">
<HintPath>..\..\..\..\..\..\Applications\Unity\Unity.app\Contents\Managed\UnityEditor.dll</HintPath>
</Reference>
<Reference Include="UnityEngine">
<HintPath>..\..\..\..\..\..\Applications\Unity\Unity.app\Contents\Managed\UnityEngine.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="BLogger.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
OmniSharp has a little bit of extra logic that will try to handle files that aren't included in a project if you make an edit in it. Essentially, if it can find a project that the file is likely to belong to, it will add it to OmniSharp's in-memory workspace. However, it won't change your project file.
@DustinCampbell @rchande Thx! If I understand your explanation correctly: it looks like every time I rename a file or create a file, we are in uncharted territory where OmniSharp need to figure out whether a file belongs to the project without checking .csproj (which is now outdated).
While I fully understand that design decision. Maybe, just maybe, we can have a per-workspace setting, where we overrule .csproj and tell OmniSharp: hey, just check every .cs file in this folder.
It's quite dumb, but for Unity users, I can't think of a better solution. (It would be a pain to ask Unity to refresh .csproj file when we are working in VS Code).
@DustinCampbell @bitinn Just restarting omnisharp after renaming doesn't work, you actually have to focus on unity3d to let it update .csprojs, and THEN reload Omnisharp/Vscode. Much fun π
After I understood the problem (and realised Omnisharp can't fix this issue in general, unity3D project system is too quirky) I took the pain to write a separate small crude extension which:
-turns on if it detects you are editing a Unity3d project -onDocumentOpen checks if the opened .cs file is not included in any .csproj project -if so, emulute Unity magic to find appropriate csproj and add missing "compile include=" line
All fine so far, The remaining issue was that omnisharp apparently doesn't listen to changes to .csproj files, so I still had to reload vscode for this to work... I forgot you can just restart omnisharp, maybe triggering that automaticaly after editing .csproj would feel smooth enough.
anyway, it would be best if o# knew how to listen to outside .csproj changes, should this in principle be similar to recent "dotnet restore" improvements?
@SirIntruder Nice work! That's very cool. Any plans to publish that extension? I bet there would be a lot of interest. For our side, I'll take a look and see if we can listen to csproj changes.
thanks! I would like to, yet didn't want to publish it if it can't work without reloading vscode. But with "restart omnisharp" approach it may actually be just good enough for small-to-medium projects. Fingers crossed for listening to .csproj changes though, would fix a lot of the issues π
if anyone is brave enough to try this, I have uploaded .vsix here. https://github.com/SirIntruder/unitysmooth/releases I can probably steal some more time for it this week
p.s. after a bit of testing, I realised omnisharp doesn't like being restarted a lot, it gets perma stuck if it doesn't "recover" fully from previous restart. Any idea on when it should be 'safe' to restart? You can see behaviour for yourself by some simple restart command spamming.
I have stumbled upon the same issue, is there any update on this?
I was debugging today and I am pretty sure what is the issue. Omnisharp correctly listens to csproj. files, that was not the problem..
Issue was omnisharp's handling of .cs files which are not in any csproj, which @DustinCampbell mentioned. IIRC it finds first folders with project files and links new/renamed file to all of the found projects in that folder. In Unity case, all of its csprojs are in root folder, so new/renamed files are added everywhere.
Problem is that those transient links are not removed when projects are updated. Unity3d, (or me manually, doesn't matter) will later on put the new/renamed file to its correct csproj, but o# will keep it in all projects.
^Here TestClassB is added to the Assembly-CSharp.csproj, but o# still keeps it in Assembly-CSharp-firstpass.csproj as well - that's some other project, which doesn't know of TestClassA.cs.
So TestClassA.cs appears to simultaneously exist and doesn't exist.
And once you reload omnisharp/vscode, that temp link B had with Assembly-CSharp-firstpass.csproj doesn't exist anymore, and that weird error is gone with it.
Does this make sense? I assume issue should be raised to omnisharp-roslyn
@SirIntruder Nice sleuthing! I think you're right--this is an Omnisharp bug. I'm the developer who will probably fix this in OmniSharp. I'm not very familiar with unity, so to help me reproduce this, would you mind sharing your repro steps? It'll just make it faster to validate that the fix works for your scenario. Thanks!
Of course! I uploaded an archive of my test project. I tried to step through omnisharp code while reproducing this, it went something like this:
TestClassA.cs is in "Assets/", which unity algorithm assigns to "assembly-csharp.csproj", and dummy.cs is in "Assets/Plugins/", which unity algorithm assigns it to "assembly-csharp-firstpass.csproj". "assembly-csharp-firstpass.csproj" never knows of "assembly-csharp.csproj"
I created "Assets/TestClassB.cs" from vscode. O# added it to both "assembly-csharp.csproj" and "assembly-csharp-firstpass.csproj". BufferManager.cs now how two documents added to _transientDocuments dictionary under "Assets/TestClassB.cs".
add line in "assembly-csharp.csproj" to include "Assets/TestClassB.cs". This invokes ProjectManager.UpdateProject. ProjectManager kills one of the two transient documents and adds a real link. This also makes BufferManager state obsolete.
BufferManager.OnWorkspaceChanged has code which looks like it should fix this issue, but it doesn't. it usually doesn't register "removing transient, adding real" as documentAdded event, and when it tries to remove all transientDocuments for "Assets/TestClassB.cs", exception occurs since one of the documentIds has already been killed.
Same issue here. I have to restart vscode each time I create a new c# file. Annoying :)
Same issue here need to restart vs code each time i rename file with a class in it
A quick recap on the workaround for future visitors:
It should solve 90% of your problem, the rest you need an Editor restart.
@bitinn Even doing that sometimes vscode has problems restarting the solution or the project and just logs project loaded without bringing the intellisense or the assembly metadata or references
You have to first focus unity, which will update project files correctly, and then restart omnisharp.
I'd love to see this fix. π
Unfortunately, as a workaround, restarting omnisharp is not great. In a pretty small project, it takes me about 8-9 seconds to see the results in the file I'm working in, and this can happen over 20-30+ times a day when you're making a decent amount of changes or doing some refactoring/cleanups.
I've run into this problem as well with VSCode + Unity and would love a fix. I can only get it to consistently work by closing and restarting VSCode every time I create a new file.
This is consistently a problem when renaming a .cs file using the right click "rename" option (F2).
What I will see is that OmniSharp will start reporting that the class in the new file is a duplicate of an existing. This can be fixed by restarting VS Code, or creating an empty file with the old file name and no content.
In my vscode only works if I focus Unity to it changes de csproj files then "Reload Windows" in vscode. Only restarting Omnisharp doesn't work, always need Unity "compiling" task.
As per https://github.com/OmniSharp/omnisharp-roslyn/pull/1159 this problem should be fixed. @SirIntruder Can you confirm if we can close this now ? Can someone here try setting "omnisharp.path": "latest" and checking if the error still persists?
OK so here is my test result with Omnisharp version 1.32.12-beta.51
.
Setup:
Test 1:
Test 2:
Conclusion:
Not sure this is by design, @SirIntruder I guess?
Yup, fIxing that would require Omsnisharp to be able to "read Unity's mind". Basically, there is code in omnisharp that takes a filePath for the new file on one hand, and list of project files on the other hand, and tries to find the most likely match. If there was a way for a plugin to be inserted at this point, it would be possible to inject Unity's magic formula and have everything work out of the box. I don't know much about omnisharp's plugin architecture though, a member of omnisharp team could comment on this.
@bitinn Thanks for the analysis! @SirIntruder is correct that OmniSharp tries to figure out what project file to associate new files with. In test 1, are you adding the file in the same directory as or a child directory of the project file Unity generates?
@rchande
In test 1, are you adding the file in the same directory as or a child directory of the project file Unity generates?
A child directory, a typical Unity repo looks something like this, and all scripts are somewhere under Assets folder (obviously can be much deeper down the hierarchy:
I should note that Test 1 doesn't reliably reproduce, I suspect it has something to do with omnisharp's extra logic that auto-detect new file or changes that wasn't in the csproj, so what's "supported" out of the box becomes a lot more muddier.
I have the same problem here on Windows 10 with version 1.32.3
Creating or renaming a new file messes Omnisharp up. Not even restarting it fixes the problem. Only solution is to restart vscode... This makes the editor almost unusable
Has there been any progress on this issue? I wouldn't want to come back to Visual Studio
Thanks
[EDIT] Problem solved: It seems that Omnisharp got confused with all dotnet versions installed in my PC.
I uninstalled all sdks, visual studio related sdks, remove path variables manually set by myself. Reinstalled vscode, dot net and omnisharp.
Everything works fine now!
Also I can confirm that Omnisharp fails when creating new files in a Unity Project. It stops finding any references, but I do not get errors, it's like Omnisharp is not running at all. Not even my code snippets can be found.
Only a restart of VSCode fixes it, but only, if the empty file is not there, anymore, either by deleting or adding contents to it.
I'm on Mac OS X.
I have the same problem and I'm wondering why Omnisharp doesn't simply add the file to a csproj that covers any file close by, this would at least work for creating files in the same directory as existing files.
Visual Studio is able to add files to an open Unity solution just fine. What is keeping omnisharp from doing the same? Or is this something that should happen on vscode project management level?
I have this problem as well (Windows 10). Whenever I add a new .cs file, there's no code completion inside it. I can't reference it in existing files either. I have to restart omisharp a lot*. This basically makes it next to unusable for me...
Any chance to get this fixed? Sadly, uninstalling all SDKs except for one is not an option for me...
EDIT: Just to make this point clear. I'm talking about creating a new .cs file within* VSCode. No external file system modifications taking place.
Any update on this?
I'm encountering the same issue where creating a new .cs file in vscode requires me to focus Unity, wait for it to compile the new changes and then go back to vscode.
I whipped out a small script that should fix this issue for Unity projects - https://gist.github.com/SirIntruder/5a8b0659df44f29b3538538a82313f66
I've tested it around a bit (Unity is at 2020.3) and it seems it works, Do tell if you encounter any problems.
Ideally, Unity should have out-of-the-box solution for this as part of vscode-editor package, I don't see a way for omnisharp to fix this properly by itself.
Here the same thing happens. I'm using a web api project. It only resolves when I restart Ommisharp.
I have the same problem on .NET MVC app. Its annoying.
Environment data
dotnet --info
output:VS Code version:
Version 1.20.1 (1.20.1)
C# Extension version:
1.14.0
Steps to reproduce
Create a file or rename a file and wait for Omnisharp to parse the file.
Expected behavior
VSCode should be able to find all existing namespace and assemblies.
Actual behavior
VSCode failed to find interfaces in the same namespace, and we can only reproduce it in current session, restarting VSCode, the issue is gone.
It seems Omnisharp somehow couldn't recognize new file or renamed file are in the same namespace.
Screenshots
Existing file:
Create a new file with simple class name change:
Problems:
Restart or reload VSCode: