set file colour in sln explorer based on git status

This commit is contained in:
Matt Parker
2025-10-30 00:18:24 +10:00
parent b5aa964106
commit 4cff69abad
5 changed files with 44 additions and 3 deletions

View File

@@ -14,6 +14,7 @@
<PackageVersion Include="ClrDebug" Version="0.3.4" /> <PackageVersion Include="ClrDebug" Version="0.3.4" />
<PackageVersion Include="FileWatcherEx" Version="2.7.0" /> <PackageVersion Include="FileWatcherEx" Version="2.7.0" />
<PackageVersion Include="Krafs.Publicizer" Version="2.3.0" /> <PackageVersion Include="Krafs.Publicizer" Version="2.3.0" />
<PackageVersion Include="LibGit2Sharp" Version="0.31.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components" Version="10.0.0-rc.2.25502.107" /> <PackageVersion Include="Microsoft.AspNetCore.Components" Version="10.0.0-rc.2.25502.107" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebView" Version="10.0.0-rc.2.25502.107" /> <PackageVersion Include="Microsoft.AspNetCore.Components.WebView" Version="10.0.0-rc.2.25502.107" />
<PackageVersion Include="Microsoft.Build" Version="18.1.0-preview-25521-106" /> <PackageVersion Include="Microsoft.Build" Version="18.1.0-preview-25521-106" />
@@ -59,4 +60,4 @@
<PackageVersion Include="Microsoft.CodeAnalysis.ExternalAccess.Razor.Features" Version="5.3.0-1.25521.106" /> <PackageVersion Include="Microsoft.CodeAnalysis.ExternalAccess.Razor.Features" Version="5.3.0-1.25521.106" />
<PackageVersion Include="Microsoft.CodeAnalysis.Remote.ServiceHub" Version="5.3.0-1.25521.106" /> <PackageVersion Include="Microsoft.CodeAnalysis.Remote.ServiceHub" Version="5.3.0-1.25521.106" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -17,6 +17,7 @@ public class SharpIdeFile : ISharpIdeNode, IChildSharpIdeNode, IFileOrFolder
public bool IsCshtmlFile => Path.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase); public bool IsCshtmlFile => Path.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase);
public bool IsCsharpFile => Path.EndsWith(".cs", StringComparison.OrdinalIgnoreCase); public bool IsCsharpFile => Path.EndsWith(".cs", StringComparison.OrdinalIgnoreCase);
public bool IsRoslynWorkspaceFile => IsCsharpFile || IsRazorFile || IsCshtmlFile; public bool IsRoslynWorkspaceFile => IsCsharpFile || IsRazorFile || IsCshtmlFile;
public GitStatus GitStatus { get; set; } = GitStatus.Unaltered;
public required ReactiveProperty<bool> IsDirty { get; init; } public required ReactiveProperty<bool> IsDirty { get; init; }
public required bool SuppressDiskChangeEvents { get; set; } // probably has concurrency issues public required bool SuppressDiskChangeEvents { get; set; } // probably has concurrency issues
public required DateTimeOffset? LastIdeWriteTime { get; set; } public required DateTimeOffset? LastIdeWriteTime { get; set; }

View File

@@ -1,4 +1,5 @@
using System.Diagnostics; using System.Diagnostics;
using LibGit2Sharp;
namespace SharpIDE.Application.Features.SolutionDiscovery.VsPersistence; namespace SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
@@ -11,7 +12,34 @@ public static class VsPersistenceMapper
var intermediateModel = await IntermediateMapper.GetIntermediateModel(solutionFilePath, cancellationToken); var intermediateModel = await IntermediateMapper.GetIntermediateModel(solutionFilePath, cancellationToken);
var solutionModel = new SharpIdeSolutionModel(solutionFilePath, intermediateModel); var solutionModel = new SharpIdeSolutionModel(solutionFilePath, intermediateModel);
using var repo = new Repository(solutionModel.DirectoryPath);
var status = repo.RetrieveStatus(new StatusOptions());
foreach (var entry in status.Where(s => s.State is not FileStatus.Ignored))
{
// Assumes solution file is at git repo root
var filePath = new FileInfo(Path.Combine(solutionModel.DirectoryPath, entry.FilePath)).FullName; // used to normalise path separators
var fileInSolution = solutionModel.AllFiles.SingleOrDefault(f => f.Path.Equals(filePath, StringComparison.OrdinalIgnoreCase));
if (fileInSolution is null) continue;
var mappedGitStatus = entry.State switch
{
FileStatus.NewInIndex | FileStatus.ModifiedInWorkdir => GitStatus.Added, // I've seen these appear together
FileStatus.NewInIndex or FileStatus.NewInWorkdir => GitStatus.Added,
FileStatus.ModifiedInIndex or FileStatus.ModifiedInWorkdir => GitStatus.Modified,
_ => GitStatus.Unaltered // TODO: handle other kinds?
};
fileInSolution.GitStatus = mappedGitStatus;
}
return solutionModel; return solutionModel;
} }
} }
public enum GitStatus
{
Unaltered,
Modified,
Added
}

View File

@@ -23,6 +23,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CliWrap" /> <PackageReference Include="CliWrap" />
<PackageReference Include="FileWatcherEx" /> <PackageReference Include="FileWatcherEx" />
<PackageReference Include="LibGit2Sharp" />
<PackageReference Include="Microsoft.Diagnostics.NETCore.Client" PrivateAssets="all" /> <PackageReference Include="Microsoft.Diagnostics.NETCore.Client" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" /> <PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" />
<PackageReference Include="Microsoft.VisualStudio.Shared.VSCodeDebugProtocol" /> <PackageReference Include="Microsoft.VisualStudio.Shared.VSCodeDebugProtocol" />

View File

@@ -26,7 +26,8 @@ public partial class SolutionExplorerPanel : MarginContainer
public Texture2D SlnIcon { get; set; } = null!; public Texture2D SlnIcon { get; set; } = null!;
private readonly Color _gitNewFileColour = new Color("50964c"); private readonly Color _gitNewFileColour = new Color("50964c");
private readonly Color _gitEditedFileColour = new Color("5988b3"); private readonly Color _gitEditedFileColour = new Color("6496ba");
private readonly Color _gitUnalteredFileColour = new Color("d4d4d4");
public SharpIdeSolutionModel SolutionModel { get; set; } = null!; public SharpIdeSolutionModel SolutionModel { get; set; } = null!;
private Tree _tree = null!; private Tree _tree = null!;
@@ -286,7 +287,8 @@ public partial class SolutionExplorerPanel : MarginContainer
{ {
var fileItem = tree.CreateItem(parent); var fileItem = tree.CreateItem(parent);
fileItem.SetText(0, sharpIdeFile.Name); fileItem.SetText(0, sharpIdeFile.Name);
fileItem.SetIcon(0, CsharpFileIcon); fileItem.SetIcon(0, CsharpFileIcon);
fileItem.SetCustomColor(0, GetColorForGitStatus(sharpIdeFile.GitStatus));
fileItem.SetMetadata(0, new RefCountedContainer<SharpIdeFile>(sharpIdeFile)); fileItem.SetMetadata(0, new RefCountedContainer<SharpIdeFile>(sharpIdeFile));
Observable.EveryValueChanged(sharpIdeFile, folder => folder.Name) Observable.EveryValueChanged(sharpIdeFile, folder => folder.Name)
@@ -302,4 +304,12 @@ public partial class SolutionExplorerPanel : MarginContainer
{ {
await this.InvokeAsync(() => item?.Free()); await this.InvokeAsync(() => item?.Free());
} }
private Color GetColorForGitStatus(GitStatus status) => status switch
{
GitStatus.Added => _gitNewFileColour,
GitStatus.Modified => _gitEditedFileColour,
GitStatus.Unaltered => _gitUnalteredFileColour,
_ => _gitUnalteredFileColour
};
} }