copy and move directories
This commit is contained in:
@@ -28,6 +28,36 @@ public class IdeFileOperationsService(SharpIdeSolutionModificationService sharpI
|
|||||||
await _sharpIdeSolutionModificationService.RemoveDirectory(folder);
|
await _sharpIdeSolutionModificationService.RemoveDirectory(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task CopyDirectory(IFolderOrProject destinationParentNode, string sourceDirectoryPath, string newDirectoryName)
|
||||||
|
{
|
||||||
|
var newDirectoryPath = Path.Combine(destinationParentNode.ChildNodeBasePath, newDirectoryName);
|
||||||
|
CopyAll(new DirectoryInfo(sourceDirectoryPath), new DirectoryInfo(newDirectoryPath));
|
||||||
|
var newFolder = await _sharpIdeSolutionModificationService.AddDirectory(destinationParentNode, newDirectoryName);
|
||||||
|
return;
|
||||||
|
|
||||||
|
static void CopyAll(DirectoryInfo source, DirectoryInfo target)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(target.FullName);
|
||||||
|
foreach (var fi in source.GetFiles())
|
||||||
|
{
|
||||||
|
fi.CopyTo(Path.Combine(target.FullName, fi.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var diSourceSubDir in source.GetDirectories())
|
||||||
|
{
|
||||||
|
var nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
|
||||||
|
CopyAll(diSourceSubDir, nextTargetSubDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task MoveDirectory(IFolderOrProject destinationParentNode, SharpIdeFolder folderToMove)
|
||||||
|
{
|
||||||
|
var newDirectoryPath = Path.Combine(destinationParentNode.ChildNodeBasePath, folderToMove.Name);
|
||||||
|
Directory.Move(folderToMove.Path, newDirectoryPath);
|
||||||
|
await _sharpIdeSolutionModificationService.MoveDirectory(destinationParentNode, folderToMove);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task DeleteFile(SharpIdeFile file)
|
public async Task DeleteFile(SharpIdeFile file)
|
||||||
{
|
{
|
||||||
File.Delete(file.Path);
|
File.Delete(file.Path);
|
||||||
|
|||||||
@@ -60,9 +60,37 @@ public class SharpIdeSolutionModificationService(FileChangedService fileChangedS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task MoveDirectory(SharpIdeFolder folder, string newDirectoryPath)
|
public async Task MoveDirectory(IFolderOrProject destinationParentNode, SharpIdeFolder folderToMove)
|
||||||
{
|
{
|
||||||
|
var oldFolderPath = folderToMove.Path;
|
||||||
|
var newFolderPath = Path.Combine(destinationParentNode.ChildNodeBasePath, folderToMove.Name);
|
||||||
|
|
||||||
|
var parentFolderOrProject = (IFolderOrProject)folderToMove.Parent;
|
||||||
|
parentFolderOrProject.Folders.Remove(folderToMove);
|
||||||
|
destinationParentNode.Folders.Add(folderToMove);
|
||||||
|
folderToMove.Parent = destinationParentNode;
|
||||||
|
folderToMove.Path = newFolderPath;
|
||||||
|
|
||||||
|
var stack = new Stack<SharpIdeFolder>();
|
||||||
|
stack.Push(folderToMove);
|
||||||
|
|
||||||
|
while (stack.Count > 0)
|
||||||
|
{
|
||||||
|
var current = stack.Pop();
|
||||||
|
|
||||||
|
foreach (var subfolder in current.Folders)
|
||||||
|
{
|
||||||
|
subfolder.Path = Path.Combine(current.Path, subfolder.Name);
|
||||||
|
stack.Push(subfolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var file in current.Files)
|
||||||
|
{
|
||||||
|
var oldPath = file.Path;
|
||||||
|
file.Path = Path.Combine(current.Path, file.Name);
|
||||||
|
await _fileChangedService.SharpIdeFileMoved(file, oldPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RenameDirectory(SharpIdeFolder folder, string renamedFolderName)
|
public async Task RenameDirectory(SharpIdeFolder folder, string renamedFolderName)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
|||||||
|
|
||||||
namespace SharpIDE.Application.Features.SolutionDiscovery;
|
namespace SharpIDE.Application.Features.SolutionDiscovery;
|
||||||
|
|
||||||
public class SharpIdeFile : ISharpIdeNode, IChildSharpIdeNode
|
public class SharpIdeFile : ISharpIdeNode, IChildSharpIdeNode, IFileOrFolder
|
||||||
{
|
{
|
||||||
public required IExpandableSharpIdeNode Parent { get; set; }
|
public required IExpandableSharpIdeNode Parent { get; set; }
|
||||||
public required string Path { get; set; }
|
public required string Path { get; set; }
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
|||||||
|
|
||||||
namespace SharpIDE.Application.Features.SolutionDiscovery;
|
namespace SharpIDE.Application.Features.SolutionDiscovery;
|
||||||
|
|
||||||
public class SharpIdeFolder : ISharpIdeNode, IExpandableSharpIdeNode, IChildSharpIdeNode, IFolderOrProject
|
public class SharpIdeFolder : ISharpIdeNode, IExpandableSharpIdeNode, IChildSharpIdeNode, IFolderOrProject, IFileOrFolder
|
||||||
{
|
{
|
||||||
public required IExpandableSharpIdeNode Parent { get; set; }
|
public required IExpandableSharpIdeNode Parent { get; set; }
|
||||||
public required string Path { get; set; }
|
public required string Path { get; set; }
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ public interface IFolderOrProject : IExpandableSharpIdeNode, IChildSharpIdeNode
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string ChildNodeBasePath { get; }
|
public string ChildNodeBasePath { get; }
|
||||||
}
|
}
|
||||||
|
public interface IFileOrFolder : IChildSharpIdeNode
|
||||||
|
{
|
||||||
|
public string Path { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
public interface IChildSharpIdeNode
|
public interface IChildSharpIdeNode
|
||||||
{
|
{
|
||||||
public IExpandableSharpIdeNode Parent { get; set; }
|
public IExpandableSharpIdeNode Parent { get; set; }
|
||||||
|
|||||||
@@ -14,11 +14,21 @@ public partial class SolutionExplorerPanel
|
|||||||
var selectedItems = GetSelectedTreeItems();
|
var selectedItems = GetSelectedTreeItems();
|
||||||
if (selectedItems.Count is 0) return;
|
if (selectedItems.Count is 0) return;
|
||||||
_itemsOnClipboard = (selectedItems
|
_itemsOnClipboard = (selectedItems
|
||||||
.Select(item => item.GetMetadata(0).As<RefCounted?>())
|
.Select(item =>
|
||||||
.OfType<RefCountedContainer<SharpIdeFile>>()
|
{
|
||||||
.Select(s => s.Item)
|
var metadata = item.GetMetadata(0).As<RefCounted?>();
|
||||||
|
IFileOrFolder? result = metadata switch
|
||||||
|
{
|
||||||
|
RefCountedContainer<SharpIdeFile> file => file.Item,
|
||||||
|
RefCountedContainer<SharpIdeFolder> folder => folder.Item,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
.OfType<IFileOrFolder>()
|
||||||
.ToList(),
|
.ToList(),
|
||||||
clipboardOperation);
|
clipboardOperation);
|
||||||
|
GD.Print($"Solution Explorer - Added {_itemsOnClipboard.Value.Item1.Count} items to clipboard with operation {clipboardOperation}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TreeItem> GetSelectedTreeItems()
|
private List<TreeItem> GetSelectedTreeItems()
|
||||||
@@ -51,18 +61,18 @@ public partial class SolutionExplorerPanel
|
|||||||
_itemsOnClipboard = null;
|
_itemsOnClipboard = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CopyNodeFromClipboardToSelectedNode()
|
private void CopyNodesFromClipboardToSelectedNode()
|
||||||
{
|
{
|
||||||
var selected = _tree.GetSelected();
|
var selected = _tree.GetSelected();
|
||||||
if (selected is null || _itemsOnClipboard is null) return;
|
if (selected is null || _itemsOnClipboard is null) return;
|
||||||
var genericMetadata = selected.GetMetadata(0).As<RefCounted?>();
|
var genericMetadata = selected.GetMetadata(0).As<RefCounted?>();
|
||||||
IFolderOrProject? folderOrProject = genericMetadata switch
|
IFolderOrProject? destinationFolderOrProject = genericMetadata switch
|
||||||
{
|
{
|
||||||
RefCountedContainer<SharpIdeFolder> f => f.Item,
|
RefCountedContainer<SharpIdeFolder> f => f.Item,
|
||||||
RefCountedContainer<SharpIdeProjectModel> p => p.Item,
|
RefCountedContainer<SharpIdeProjectModel> p => p.Item,
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
if (folderOrProject is null) return;
|
if (destinationFolderOrProject is null) return;
|
||||||
|
|
||||||
var (filesToPaste, operation) = _itemsOnClipboard.Value;
|
var (filesToPaste, operation) = _itemsOnClipboard.Value;
|
||||||
_itemsOnClipboard = null;
|
_itemsOnClipboard = null;
|
||||||
@@ -70,17 +80,31 @@ public partial class SolutionExplorerPanel
|
|||||||
{
|
{
|
||||||
if (operation is ClipboardOperation.Copy)
|
if (operation is ClipboardOperation.Copy)
|
||||||
{
|
{
|
||||||
foreach (var fileToPaste in filesToPaste)
|
foreach (var fileOrFolderToPaste in filesToPaste)
|
||||||
{
|
{
|
||||||
await _ideFileOperationsService.CopyFile(folderOrProject, fileToPaste.Path, fileToPaste.Name);
|
if (fileOrFolderToPaste is SharpIdeFolder folderToPaste)
|
||||||
|
{
|
||||||
|
await _ideFileOperationsService.CopyDirectory(destinationFolderOrProject, folderToPaste.Path, folderToPaste.Name);
|
||||||
|
}
|
||||||
|
else if (fileOrFolderToPaste is SharpIdeFile fileToPaste)
|
||||||
|
{
|
||||||
|
await _ideFileOperationsService.CopyFile(destinationFolderOrProject, fileToPaste.Path, fileToPaste.Name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// This will blow up if cutting a file into a directory that already has a file with the same name, but I don't really want to handle renaming cut-pasted files for MVP
|
// This will blow up if cutting a file into a directory that already has a file with the same name, but I don't really want to handle renaming cut-pasted files for MVP
|
||||||
else if (operation is ClipboardOperation.Cut)
|
else if (operation is ClipboardOperation.Cut)
|
||||||
{
|
{
|
||||||
foreach (var fileToPaste in filesToPaste)
|
foreach (var fileOrFolderToPaste in filesToPaste)
|
||||||
{
|
{
|
||||||
await _ideFileOperationsService.MoveFile(folderOrProject, fileToPaste);
|
if (fileOrFolderToPaste is SharpIdeFolder folderToPaste)
|
||||||
|
{
|
||||||
|
await _ideFileOperationsService.MoveDirectory(destinationFolderOrProject, folderToPaste);
|
||||||
|
}
|
||||||
|
else if (fileOrFolderToPaste is SharpIdeFile fileToPaste)
|
||||||
|
{
|
||||||
|
await _ideFileOperationsService.MoveFile(destinationFolderOrProject, fileToPaste);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public partial class SolutionExplorerPanel : MarginContainer
|
|||||||
private TreeItem _rootItem = null!;
|
private TreeItem _rootItem = null!;
|
||||||
private enum ClipboardOperation { Cut, Copy }
|
private enum ClipboardOperation { Cut, Copy }
|
||||||
|
|
||||||
private (List<SharpIdeFile>, ClipboardOperation)? _itemsOnClipboard;
|
private (List<IFileOrFolder>, ClipboardOperation)? _itemsOnClipboard;
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
_tree = GetNode<Tree>("Tree");
|
_tree = GetNode<Tree>("Tree");
|
||||||
@@ -52,7 +52,7 @@ public partial class SolutionExplorerPanel : MarginContainer
|
|||||||
// Paste
|
// Paste
|
||||||
else if (@event is InputEventKey { Pressed: true, Keycode: Key.V, CtrlPressed: true })
|
else if (@event is InputEventKey { Pressed: true, Keycode: Key.V, CtrlPressed: true })
|
||||||
{
|
{
|
||||||
CopyNodeFromClipboardToSelectedNode();
|
CopyNodesFromClipboardToSelectedNode();
|
||||||
}
|
}
|
||||||
else if (@event is InputEventKey { Pressed: true, Keycode: Key.Delete })
|
else if (@event is InputEventKey { Pressed: true, Keycode: Key.Delete })
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user