more file operations
This commit is contained in:
@@ -749,6 +749,17 @@ public class RoslynAnalysis
|
||||
|
||||
var project = _workspace!.CurrentSolution.Projects.Single(s => s.FilePath == ((IChildSharpIdeNode)fileModel).GetNearestProjectNode()!.FilePath);
|
||||
|
||||
var existingDocument = fileModel switch
|
||||
{
|
||||
{ IsRazorFile: true } => project.AdditionalDocuments.SingleOrDefault(s => s.FilePath == fileModel.Path),
|
||||
{ IsCsharpFile: true } => project.Documents.SingleOrDefault(s => s.FilePath == fileModel.Path),
|
||||
_ => throw new InvalidOperationException("AddDocument failed: File is not a workspace file")
|
||||
};
|
||||
if (existingDocument is not null)
|
||||
{
|
||||
throw new InvalidOperationException($"AddDocument failed: Document '{fileModel.Path}' already exists in workspace");
|
||||
}
|
||||
|
||||
var sourceText = SourceText.From(content, Encoding.UTF8);
|
||||
|
||||
var newSolution = fileModel switch
|
||||
@@ -760,4 +771,29 @@ public class RoslynAnalysis
|
||||
|
||||
_workspace.TryApplyChanges(newSolution);
|
||||
}
|
||||
|
||||
public async Task RemoveDocument(SharpIdeFile fileModel)
|
||||
{
|
||||
using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(AddDocument)}");
|
||||
await _solutionLoadedTcs.Task;
|
||||
Guard.Against.Null(fileModel, nameof(fileModel));
|
||||
|
||||
var project = _workspace!.CurrentSolution.Projects.Single(s => s.FilePath == ((IChildSharpIdeNode)fileModel).GetNearestProjectNode()!.FilePath);
|
||||
|
||||
var document = fileModel switch
|
||||
{
|
||||
{ IsRazorFile: true } => project.AdditionalDocuments.Single(s => s.FilePath == fileModel.Path),
|
||||
{ IsCsharpFile: true } => project.Documents.Single(s => s.FilePath == fileModel.Path),
|
||||
_ => throw new InvalidOperationException("UpdateDocument failed: File is not in workspace")
|
||||
};
|
||||
|
||||
var newSolution = fileModel switch
|
||||
{
|
||||
{ IsRazorFile: true } => _workspace.CurrentSolution.RemoveAdditionalDocument(document.Id),
|
||||
{ IsCsharpFile: true } => _workspace.CurrentSolution.RemoveDocument(document.Id),
|
||||
_ => throw new InvalidOperationException("AddDocument failed: File is not in workspace")
|
||||
};
|
||||
|
||||
_workspace.TryApplyChanges(newSolution);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,14 @@ public class FileChangedService(RoslynAnalysis roslynAnalysis, IdeOpenTabsFileMa
|
||||
// TODO: handle csproj added
|
||||
}
|
||||
|
||||
public async Task SharpIdeFileRemoved(SharpIdeFile file)
|
||||
{
|
||||
if (file.IsRoslynWorkspaceFile)
|
||||
{
|
||||
await HandleWorkspaceFileRemoved(file);
|
||||
}
|
||||
}
|
||||
|
||||
// All file changes should go via this service
|
||||
public async Task SharpIdeFileChanged(SharpIdeFile file, string newContents, FileChangeType changeType)
|
||||
{
|
||||
@@ -106,4 +114,15 @@ public class FileChangedService(RoslynAnalysis roslynAnalysis, IdeOpenTabsFileMa
|
||||
GlobalEvents.Instance.SolutionAltered.InvokeParallelFireAndForget();
|
||||
await _roslynAnalysis.UpdateSolutionDiagnostics(newCts.Token);
|
||||
}
|
||||
|
||||
private async Task HandleWorkspaceFileRemoved(SharpIdeFile file)
|
||||
{
|
||||
var newCts = new CancellationTokenSource();
|
||||
var oldCts = Interlocked.Exchange(ref _updateSolutionDiagnosticsCts, newCts);
|
||||
await oldCts.CancelAsync();
|
||||
oldCts.Dispose();
|
||||
await _roslynAnalysis.RemoveDocument(file);
|
||||
GlobalEvents.Instance.SolutionAltered.InvokeParallelFireAndForget();
|
||||
await _roslynAnalysis.UpdateSolutionDiagnostics(newCts.Token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
using SharpIDE.Application.Features.SolutionDiscovery;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SharpIDE.Application.Features.SolutionDiscovery;
|
||||
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||
|
||||
namespace SharpIDE.Application.Features.FileWatching;
|
||||
|
||||
/// Does not do any file system operations, only modifies the in-memory solution model
|
||||
public class SharpIdeSolutionModificationService
|
||||
public class SharpIdeSolutionModificationService(FileChangedService fileChangedService)
|
||||
{
|
||||
private readonly FileChangedService _fileChangedService = fileChangedService;
|
||||
|
||||
public SharpIdeSolutionModel SolutionModel { get; set; } = null!;
|
||||
|
||||
/// The directory must already exist on disk
|
||||
public async Task<SharpIdeFolder> AddDirectory(SharpIdeFolder parentFolder, string directoryName)
|
||||
{
|
||||
// Passing [] to allFiles and allFolders, as we assume that a brand new folder has no subfolders or files yet
|
||||
var addedDirectoryPath = Path.Combine(parentFolder.Path, directoryName);
|
||||
var sharpIdeFolder = new SharpIdeFolder(new DirectoryInfo(addedDirectoryPath), parentFolder, [], []);
|
||||
var allFiles = new ConcurrentBag<SharpIdeFile>();
|
||||
var allFolders = new ConcurrentBag<SharpIdeFolder>();
|
||||
var sharpIdeFolder = new SharpIdeFolder(new DirectoryInfo(addedDirectoryPath), parentFolder, allFiles, allFolders);
|
||||
parentFolder.Folders.Add(sharpIdeFolder);
|
||||
SolutionModel.AllFolders.Add(sharpIdeFolder);
|
||||
SolutionModel.AllFolders.AddRange((IEnumerable<SharpIdeFolder>)[sharpIdeFolder, ..allFolders]);
|
||||
SolutionModel.AllFiles.AddRange(allFiles);
|
||||
return sharpIdeFolder;
|
||||
}
|
||||
|
||||
@@ -23,6 +29,30 @@ public class SharpIdeSolutionModificationService
|
||||
{
|
||||
var parentFolderOrProject = (IFolderOrProject)folder.Parent;
|
||||
parentFolderOrProject.Folders.Remove(folder);
|
||||
SolutionModel.AllFolders.Remove(folder);
|
||||
|
||||
// Also remove all child files and folders from SolutionModel.AllFiles and AllFolders
|
||||
var foldersToRemove = new List<SharpIdeFolder>();
|
||||
|
||||
var stack = new Stack<SharpIdeFolder>();
|
||||
stack.Push(folder);
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
var current = stack.Pop();
|
||||
foldersToRemove.Add(current);
|
||||
|
||||
foreach (var subfolder in current.Folders)
|
||||
{
|
||||
stack.Push(subfolder);
|
||||
}
|
||||
}
|
||||
|
||||
var filesToRemove = foldersToRemove.SelectMany(f => f.Files).ToList();
|
||||
|
||||
SolutionModel.AllFiles.RemoveRange(filesToRemove);
|
||||
SolutionModel.AllFolders.RemoveRange(foldersToRemove);
|
||||
foreach (var file in filesToRemove)
|
||||
{
|
||||
await _fileChangedService.SharpIdeFileRemoved(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user