diff --git a/src/SharpIDE.Application/Features/SolutionDiscovery/FileOrFolder.cs b/src/SharpIDE.Application/Features/SolutionDiscovery/FileOrFolder.cs new file mode 100644 index 0000000..f75513b --- /dev/null +++ b/src/SharpIDE.Application/Features/SolutionDiscovery/FileOrFolder.cs @@ -0,0 +1,18 @@ +namespace SharpIDE.Application.Features.SolutionDiscovery; + +public class SharpIdeFile +{ + public required string Path { get; set; } + public required string Name { get; set; } +} + +public class SharpIdeFolder +{ + public required string Path { get; set; } + public required string Name { get; set; } + public required List Files { get; set; } + public required List Folders { get; set; } + // public required int Depth { get; set; } + + public bool Expanded { get; set; } +} diff --git a/src/SharpIDE.Application/Features/SolutionDiscovery/TreeMapV2.cs b/src/SharpIDE.Application/Features/SolutionDiscovery/TreeMapV2.cs new file mode 100644 index 0000000..37b133c --- /dev/null +++ b/src/SharpIDE.Application/Features/SolutionDiscovery/TreeMapV2.cs @@ -0,0 +1,86 @@ +using System.Collections.Concurrent; +using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence; + +namespace SharpIDE.Application.Features.SolutionDiscovery; + +public static class TreeMapperV2 +{ + public static List GetSubFolders(string csprojectPath) + { + var projectDirectory = Path.GetDirectoryName(csprojectPath)!; + var rootFolder = new SharpIdeFolder + { + Path = projectDirectory, + Name = null!, + Files = [], + Folders = [] + }; + var subFolders = rootFolder.GetSubFolders(); + return subFolders; + } + public static List GetSubFolders(this SharpIdeFolder folder) + { + var directoryInfo = new DirectoryInfo(folder.Path); + ConcurrentBag subFolders = []; + + List subFolderInfos; + try + { + subFolderInfos = directoryInfo.EnumerateDirectories("*", new EnumerationOptions + { + IgnoreInaccessible = false, + AttributesToSkip = FileAttributes.ReparsePoint + }).ToList(); + } + catch (UnauthorizedAccessException) + { + return subFolders.ToList(); + } + + Parallel.ForEach(subFolderInfos, subFolderInfo => + { + var subFolder = new SharpIdeFolder + { + Path = subFolderInfo.FullName, + Name = subFolderInfo.Name, + Files = GetFiles(subFolderInfo), + Folders = new SharpIdeFolder + { + Path = subFolderInfo.FullName, + Name = subFolderInfo.Name, + Files = [], + Folders = [] + }.GetSubFolders() + }; + + subFolders.Add(subFolder); + }); + + return subFolders.ToList(); + } + + public static List GetFiles(string csprojectPath) + { + var projectDirectory = Path.GetDirectoryName(csprojectPath)!; + var directoryInfo = new DirectoryInfo(projectDirectory); + return GetFiles(directoryInfo); + } + public static List GetFiles(DirectoryInfo directoryInfo) + { + List fileInfos; + try + { + fileInfos = directoryInfo.EnumerateFiles().ToList(); + } + catch (UnauthorizedAccessException) + { + return []; + } + + return fileInfos.Select(f => new SharpIdeFile + { + Path = f.FullName, + Name = f.Name + }).ToList(); + } +} diff --git a/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/IntermediateModels.cs b/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/IntermediateModels.cs index c27475c..1f1a18f 100644 --- a/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/IntermediateModels.cs +++ b/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/IntermediateModels.cs @@ -21,4 +21,5 @@ public class IntermediateProjectModel { public required SolutionProjectModel Model { get; set; } public required string FullFilePath { get; set; } + public required Guid Id { get; set; } } diff --git a/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/SharpIdeModels.cs b/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/SharpIdeModels.cs index e548fc6..178ed9d 100644 --- a/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/SharpIdeModels.cs +++ b/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/SharpIdeModels.cs @@ -17,4 +17,6 @@ public class SharpIdeProjectModel { public required string Name { get; set; } public required string FilePath { get; set; } + public required List Folders { get; set; } + public required List Files { get; set; } } diff --git a/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/VsPersistenceMapper.cs b/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/VsPersistenceMapper.cs index dc4585f..2154a3c 100644 --- a/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/VsPersistenceMapper.cs +++ b/src/SharpIDE.Application/Features/SolutionDiscovery/VsPersistence/VsPersistenceMapper.cs @@ -27,11 +27,14 @@ public static class VsPersistenceMapper return solutionModel; } - private static SharpIdeProjectModel GetSharpIdeProjectModel(IntermediateProjectModel projectModel) => new SharpIdeProjectModel() - { - Name = projectModel.Model.DisplayName!, - FilePath = projectModel.Model.FilePath, - }; + private static SharpIdeProjectModel GetSharpIdeProjectModel(IntermediateProjectModel projectModel) => new SharpIdeProjectModel + { + Name = projectModel.Model.ActualDisplayName, + FilePath = projectModel.Model.FilePath, + Files = TreeMapperV2.GetFiles(projectModel.FullFilePath), + Folders = TreeMapperV2.GetSubFolders(projectModel.FullFilePath) + + }; private static SharpIdeSolutionFolder GetSharpIdeSolutionFolder(IntermediateSlnFolderModel folderModel) => new SharpIdeSolutionFolder() { @@ -49,7 +52,7 @@ public static class VsPersistenceMapper var rootFolders = vsSolution.SolutionFolders .Where(f => f.Parent is null) - .Select(f => BuildFolderTree(f, vsSolution.SolutionFolders, vsSolution.SolutionProjects)) + .Select(f => BuildFolderTree(f, solutionFilePath, vsSolution.SolutionFolders, vsSolution.SolutionProjects)) .ToList(); var solutionModel = new IntermediateSolutionModel @@ -59,19 +62,20 @@ public static class VsPersistenceMapper Projects = vsSolution.SolutionProjects.Where(p => p.Parent is null).Select(s => new IntermediateProjectModel { Model = s, - FullFilePath = Path.GetFullPath(s.FilePath) + Id = s.Id, + FullFilePath = new DirectoryInfo(Path.Join(Path.GetDirectoryName(solutionFilePath), s.FilePath)).FullName }).ToList(), SolutionFolders = rootFolders }; return solutionModel; } - private static IntermediateSlnFolderModel BuildFolderTree(SolutionFolderModel folder, + private static IntermediateSlnFolderModel BuildFolderTree(SolutionFolderModel folder, string solutionFilePath, IReadOnlyList allSolutionFolders, IReadOnlyList allSolutionProjects) { var childFolders = allSolutionFolders .Where(f => f.Parent == folder) - .Select(f => BuildFolderTree(f, allSolutionFolders, allSolutionProjects)) + .Select(f => BuildFolderTree(f, solutionFilePath, allSolutionFolders, allSolutionProjects)) .ToList(); var projectsInFolder = allSolutionProjects @@ -79,7 +83,8 @@ public static class VsPersistenceMapper .Select(s => new IntermediateProjectModel { Model = s, - FullFilePath = Path.GetFullPath(s.FilePath) + Id = s.Id, + FullFilePath = new DirectoryInfo(Path.Join(Path.GetDirectoryName(solutionFilePath), s.FilePath)).FullName }) .ToList(); diff --git a/src/SharpIDE.Photino/Components/SolutionExplorer.razor b/src/SharpIDE.Photino/Components/SolutionExplorer.razor index 8da037f..db21d40 100644 --- a/src/SharpIDE.Photino/Components/SolutionExplorer.razor +++ b/src/SharpIDE.Photino/Components/SolutionExplorer.razor @@ -1,18 +1,23 @@ -@using Ardalis.GuardClauses -@using Microsoft.Build.Construction -@using SharpIDE.Application.Features.SolutionDiscovery +@using SharpIDE.Application.Features.SolutionDiscovery @using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence -@if (_solutionFile is null) +@if (SolutionModel is null) { return; } - - - @foreach(var project in _rootNodes) - { - @GetProjectFragment(project) - } + + + + @foreach (var folder in SolutionModel.Folders) + { + @GetSolutionFolderFragment(folder) + } + @foreach(var project in SolutionModel.Projects) + { + @GetProjectFragment(project) + } + + @@ -23,71 +28,56 @@ [Parameter, EditorRequired] public SharpIdeSolutionModel SolutionModel { get; set; } = null!; - private SolutionFile _solutionFile = null!; - private List _rootNodes = []; - private Dictionary _folders = new(); - - private RenderFragment GetProjectFragment(ProjectInSolution project) => + private RenderFragment GetSolutionFolderFragment(SharpIdeSolutionFolder slnFolder) => @ - - @foreach(var child in _solutionFile.ProjectsByGuid.Values.Where(s => s.ParentProjectGuid == project.ProjectGuid).OrderBy(s => s.ProjectName)) + + @foreach(var childFolder in slnFolder.Folders) { - @GetProjectFragment(child) + @GetSolutionFolderFragment(childFolder) } - @if (_folders.GetValueOrDefault(project.ProjectGuid, null) is {} value) + @foreach(var childProject in slnFolder.Projects) { - @GetFolderFragment(value) + @GetProjectFragment(childProject) } - ; + ; - private RenderFragment GetFolderFragment(Folder folder) => + private RenderFragment GetProjectFragment(SharpIdeProjectModel project) => @ - @foreach (var subFolder in folder.Folders) - { - - @if (subFolder.Expanded) - { - @GetFolderFragment(subFolder) - } - - } - @foreach (var file in folder.Files) - { - - } - ; + + @foreach (var folder in project.Folders) + { + + @GetFolderFragment(folder) + + } + @foreach(var file in project.Files) + { + @GetFileFragment(file) + } + + ; - protected override async Task OnInitializedAsync() - { - Guard.Against.NullOrWhiteSpace(SolutionFilePath); - await Task.Run(() => LoadSolution(SolutionFilePath)); - } + private RenderFragment GetFolderFragment(SharpIdeFolder folder) => + @ + @foreach (var subFolder in folder.Folders) + { + + @if (subFolder.Expanded) + { + @GetFolderFragment(subFolder) + } + + } + @foreach (var file in folder.Files) + { + @GetFileFragment(file) + } + ; - private void LoadSolution(string solutionPath) - { - var solutionFile = GetNodesInSolution.ParseSolutionFileFromPath(solutionPath); - ArgumentNullException.ThrowIfNull(solutionFile); - _solutionFile = solutionFile; - var rootNodes = solutionFile.ProjectsByGuid.Values.Where(p => p.ParentProjectGuid == null).OrderBy(s => s.ProjectName).ToList(); - _rootNodes = rootNodes; - - var folders2 = _solutionFile.ProjectsByGuid.Values - .Where(s => s.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat) - //.Take(2) - .Select(s => - { - var rootFolder = new Folder - { - Name = Path.GetFileNameWithoutExtension(s.AbsolutePath), - Path = Path.GetDirectoryName(s.AbsolutePath)!, - IsPseudoFolder = false - }; - rootFolder.Folders = rootFolder.GetSubFolders(); - return (s, rootFolder); - }) - .ToDictionary(s => s.s.ProjectGuid, s => s.Item2); - _folders = folders2!; - } + private RenderFragment GetFileFragment(SharpIdeFile file) => + @ + + ; } diff --git a/src/SharpIDE.Photino/Layout/MainLayout.razor b/src/SharpIDE.Photino/Layout/MainLayout.razor index eff190b..1a4c0c8 100644 --- a/src/SharpIDE.Photino/Layout/MainLayout.razor +++ b/src/SharpIDE.Photino/Layout/MainLayout.razor @@ -22,7 +22,7 @@ @* @Body *@ @if (_solutionFilePath is not null) { - + } @@ -48,7 +48,7 @@ var solutionFilePath = (string)result.Data!; _solutionFilePath = solutionFilePath; - await BuildService.BuildSolutionAsync(_solutionFilePath); + //await BuildService.BuildSolutionAsync(_solutionFilePath); var solutionModel = await VsPersistenceMapper.GetSolutionModel(_solutionFilePath); _solutionModel = solutionModel; }