-
Notifications
You must be signed in to change notification settings - Fork 420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Renamed documents should be removed from the workspace and not cached #783
Renamed documents should be removed from the workspace and not cached #783
Conversation
This should sort of work, though it's a bit weird and pretty inefficient. I have a few concerns with this solution:
The right solution is to expand the /fileschanged end point or add a new end point that properly reports the file change that occurred. So, VS Code (and other editors) should just tell OmniSharp when a file was renamed instead of reporting that "something changed" and rely on OmniSharp to guess what happened. |
@DustinCampbell how do File Watchers look like on mono today? (Me not having a mac...) The real fix would be to have our own file watcher, so that we can respond to these events ourselves, but the reason we did not do that, was simply because the mono file watcher had some weird limits. |
No idea, though even the manual file watcher should have more nuance than just "a change occurred". |
@DustinCampbell it is a bit of a weird way to do it as i said. Address issue, 1. It is just removing the files when they do not exists any longer and the file change events that already fire put the new document in (hence the reason for the entire issue) Happy to make changes to get it done, because this issue was a pain point for me |
@DustinCampbell This is still an issue in the current release. Is there anything I can do to get a fix in for this or it is already in current master? |
Sorry for the delay @eByte23. As I mentioned before, this change should "work" most of the time, it leaves the workspace in a temporarily inconsistent state, which I'm really not a fan of. That can cause other strange issues later because the file won't get re-added unless the user actually edits it. I have a branch where I've been working on expanding this endpoint to include information about files deleted/added. I only did a cursory review before and left some feedback above. I'll go ahead and do a full code review now. |
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis; | ||
using OmniSharp.FileWatching; | ||
using OmniSharp.Mef; | ||
using OmniSharp.Models; | ||
using OmniSharp.Models.FilesChanged; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary blank line.
namespace OmniSharp.Roslyn.CSharp.Services.Files | ||
{ | ||
[OmniSharpHandler(OmniSharpEndpoints.FilesChanged, LanguageNames.CSharp)] | ||
public class OnFilesChangedService : IRequestHandler<IEnumerable<Request>, FilesChangedResponse> | ||
{ | ||
private readonly IFileSystemWatcher _watcher; | ||
private OmniSharpWorkspace _workspace; | ||
private object _lock = new object(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these fields should be readonly
|
||
if(!File.Exists(document.FilePath) && _workspace.CurrentSolution.ContainsDocument(document.Id)) | ||
{ | ||
_workspace.TryApplyChanges(_workspace.CurrentSolution.RemoveDocument(document.Id)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the wrong approach and can possible fail if multiple documents are removed from different projects. The reason for this is because _worksapce.TryApplyChanges(...)
will update _workspace.CurrentSolution
. However, the foreach loop will have received an enumerator from the original Solution.
I recommend the following approach:
- Capture
_workspace.CurrentSolution
into a local variable. - Loop through all its projects and documents and make necessary changes to a new Solution.
- After the loop, call
_workpsace.TryApplyChanges
with the new Solution if it is different than the old Solution.
Because all of this is done on immutable data structures (except the workspace itself), you shouldn't need the lock at all. Instead, it should be something like this (modulo errors because I'm tying into GitHub):
var directoryName = Path.GetDirectoryName(fileName);
var oldSolution = _workspace.CurrentSolution;
var newSolution = oldSolution;
foreach (var project in oldSolution.Projects)
{
if (!directoryName.StartsWith(Path.GetDirectoryName(project.FilePath), StringComparison.OrdinalIgnoreCase))
{
continue;
}
foreach (var document in project.Documents)
{
if (fileName.Equals(document.FilePath, StringComparison.OrdinalIgnoreCase) &&
!File.Exists(fileName))
{
newSolution = newSolution.RemoveDocument(document.Id);
}
}
}
if (oldSolution != newSolution)
{
_workspace.TryApplyChanges(newSolution);
}
var path = Path.GetDirectoryName(fileName); | ||
foreach (var project in _workspace.CurrentSolution.Projects) | ||
{ | ||
if (!path.StartsWith(Path.GetDirectoryName(project.FilePath))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
StringComparison.OrdinalIgnoreCase
|
||
foreach (var document in project.Documents) | ||
{ | ||
if (!document.FilePath.Contains(path)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be Equals, not Contains. I don't want to accidentally remove Foo.xaml.cs
when Foo.xaml
is removed. Also, StringComparison.OrdinalIgnoreCase
.
continue; | ||
} | ||
|
||
if(!File.Exists(document.FilePath) && _workspace.CurrentSolution.ContainsDocument(document.Id)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you change the loop to stop accessing _workspace.CurrentSolution
all of the time, the call to ContainsDocument
is unnecessary.
@DustinCampbell Thanks for the reply and the review, when I get a chance this week a shall make the changes as you have said and do some testing. Thanks! |
@DustinCampbell Sorry its been so long outstanding. I'll get onto this today and try and make the changes as requested. Should this target Master or Dev? as I notice there was a branch target change |
@eByte23 |
cc @rchande |
@eByte23 I also took a stab at this with a slightly different approach--I chose to augment the VS Code file watching to send us notifications of file creations/deletions so we could manipulate the workspace appropriately. Let me know if you have any thoughts for me: |
@rchande Thanks for the work! It will certainly help but in the circumstance that a fileChange event doesn't fire which sometimes may occur with file watchers as generally they have had a long history of not being 100% reliable (I could be wrong now, just from previous experience). If we also handle a check to clean "expired" files you could say, the atleast if and event is missed then roslyn side will automatically clean up as well. Thoughts? |
This fixes dotnet/vscode-csharp#785
Not sure if its the best way to do it but it fixed my issue