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 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 sourceText = SourceText.From(content, Encoding.UTF8);
|
||||||
|
|
||||||
var newSolution = fileModel switch
|
var newSolution = fileModel switch
|
||||||
@@ -760,4 +771,29 @@ public class RoslynAnalysis
|
|||||||
|
|
||||||
_workspace.TryApplyChanges(newSolution);
|
_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
|
// TODO: handle csproj added
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SharpIdeFileRemoved(SharpIdeFile file)
|
||||||
|
{
|
||||||
|
if (file.IsRoslynWorkspaceFile)
|
||||||
|
{
|
||||||
|
await HandleWorkspaceFileRemoved(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// All file changes should go via this service
|
// All file changes should go via this service
|
||||||
public async Task SharpIdeFileChanged(SharpIdeFile file, string newContents, FileChangeType changeType)
|
public async Task SharpIdeFileChanged(SharpIdeFile file, string newContents, FileChangeType changeType)
|
||||||
{
|
{
|
||||||
@@ -106,4 +114,15 @@ public class FileChangedService(RoslynAnalysis roslynAnalysis, IdeOpenTabsFileMa
|
|||||||
GlobalEvents.Instance.SolutionAltered.InvokeParallelFireAndForget();
|
GlobalEvents.Instance.SolutionAltered.InvokeParallelFireAndForget();
|
||||||
await _roslynAnalysis.UpdateSolutionDiagnostics(newCts.Token);
|
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;
|
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||||
|
|
||||||
namespace SharpIDE.Application.Features.FileWatching;
|
namespace SharpIDE.Application.Features.FileWatching;
|
||||||
|
|
||||||
/// Does not do any file system operations, only modifies the in-memory solution model
|
/// 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!;
|
public SharpIdeSolutionModel SolutionModel { get; set; } = null!;
|
||||||
|
|
||||||
/// The directory must already exist on disk
|
/// The directory must already exist on disk
|
||||||
public async Task<SharpIdeFolder> AddDirectory(SharpIdeFolder parentFolder, string directoryName)
|
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 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);
|
parentFolder.Folders.Add(sharpIdeFolder);
|
||||||
SolutionModel.AllFolders.Add(sharpIdeFolder);
|
SolutionModel.AllFolders.AddRange((IEnumerable<SharpIdeFolder>)[sharpIdeFolder, ..allFolders]);
|
||||||
|
SolutionModel.AllFiles.AddRange(allFiles);
|
||||||
return sharpIdeFolder;
|
return sharpIdeFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,6 +29,30 @@ public class SharpIdeSolutionModificationService
|
|||||||
{
|
{
|
||||||
var parentFolderOrProject = (IFolderOrProject)folder.Parent;
|
var parentFolderOrProject = (IFolderOrProject)folder.Parent;
|
||||||
parentFolderOrProject.Folders.Remove(folder);
|
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