Add file system watcher v1
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
<PropertyGroup>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
|
||||
<!-- We are not using package source mapping. -->
|
||||
<NoWarn>$(NoWarn);NU1507</NoWarn>
|
||||
<!-- We are not using package source mapping. -->
|
||||
<NoWarn>$(NoWarn);NU1507</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Ardalis.GuardClauses" Version="5.0.0" />
|
||||
@@ -12,6 +12,7 @@
|
||||
<PackageVersion Include="BlazorMonaco" Version="3.3.0" />
|
||||
<PackageVersion Include="CliWrap" Version="3.9.0" />
|
||||
<PackageVersion Include="ClrDebug" Version="0.3.4" />
|
||||
<PackageVersion Include="FileWatcherEx" Version="2.7.0" />
|
||||
<PackageVersion Include="Krafs.Publicizer" Version="2.3.0" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Components" Version="10.0.0-rc.1.25451.107" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Components.WebView" Version="10.0.0-rc.1.25451.107" />
|
||||
@@ -24,6 +25,7 @@
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0-2.25465.103" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Features" Version="5.0.0-2.25465.103" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.0.0-2.25465.103" />
|
||||
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="10.0.0-rc.1.25451.107" />
|
||||
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="8.0.0" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Razor.Utilities.Shared" Version="10.0.0-preview.25465.103" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Features" Version="5.0.0-2.25465.103" />
|
||||
@@ -46,14 +48,14 @@
|
||||
<PackageVersion Include="R3" Version="1.3.0" />
|
||||
<PackageVersion Include="XtermBlazor" Version="2.1.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Aspire">
|
||||
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
|
||||
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
|
||||
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
|
||||
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Aspire">
|
||||
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
|
||||
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
|
||||
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
|
||||
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Pinned Transitive Dependencies">
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.ExternalAccess.Razor.Features" Version="5.0.0-2.25465.103" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Remote.ServiceHub" Version="5.0.0-2.25465.103" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -0,0 +1,93 @@
|
||||
using FileWatcherEx;
|
||||
using Microsoft.Extensions.FileSystemGlobbing;
|
||||
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||
|
||||
namespace SharpIDE.Application.Features.FileWatching;
|
||||
|
||||
public sealed class IdeFileWatcher : IDisposable
|
||||
{
|
||||
private Matcher? _matcher;
|
||||
private FileSystemWatcherEx? _fileWatcher;
|
||||
private SharpIdeSolutionModel? _solution;
|
||||
|
||||
public void StartWatching(SharpIdeSolutionModel solution)
|
||||
{
|
||||
_solution = solution;
|
||||
|
||||
var matcher = new Matcher();
|
||||
//matcher.AddIncludePatterns(["**/*.cs", "**/*.csproj", "**/*.sln"]);
|
||||
matcher.AddIncludePatterns(["**/*"]);
|
||||
matcher.AddExcludePatterns(["**/bin", "**/obj", "**/node_modules", "**/.vs", "**/.git", "**/.idea", "**/.vscode"]);
|
||||
_matcher = matcher;
|
||||
|
||||
var fileWatcher = new FileSystemWatcherEx();
|
||||
fileWatcher.FolderPath = solution.DirectoryPath;
|
||||
//fileWatcher.Filters.AddRange(["*"]);
|
||||
fileWatcher.IncludeSubdirectories = true;
|
||||
fileWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
|
||||
fileWatcher.OnChanged += OnEvent;
|
||||
fileWatcher.OnCreated += OnEvent;
|
||||
fileWatcher.OnDeleted += OnEvent;
|
||||
fileWatcher.OnRenamed += OnEvent;
|
||||
|
||||
fileWatcher.Start();
|
||||
_fileWatcher = fileWatcher;
|
||||
}
|
||||
|
||||
public void StopWatching()
|
||||
{
|
||||
if (_fileWatcher is not null)
|
||||
{
|
||||
_fileWatcher.Stop();
|
||||
_fileWatcher.Dispose();
|
||||
_fileWatcher = null!;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Put events on a queue and process them in the background to avoid filling the buffer? FileSystemWatcherEx might already handle this
|
||||
private void OnEvent(object? sender, FileChangedEvent e)
|
||||
{
|
||||
var matchResult = _matcher!.Match(_solution!.DirectoryPath, e.FullPath);
|
||||
if (!matchResult.HasMatches) return;
|
||||
switch (e.ChangeType)
|
||||
{
|
||||
case ChangeType.CHANGED: HandleChanged(e.FullPath); break;
|
||||
case ChangeType.CREATED: HandleCreated(e.FullPath); break;
|
||||
case ChangeType.DELETED: HandleDeleted(e.FullPath); break;
|
||||
case ChangeType.RENAMED: HandleRenamed(e.OldFullPath, e.FullPath); break;
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleRenamed(string? oldFullPath, string fullPath)
|
||||
{
|
||||
|
||||
Console.WriteLine($"FileSystemWatcher: Renamed - {oldFullPath}, {fullPath}");
|
||||
}
|
||||
|
||||
private void HandleDeleted(string fullPath)
|
||||
{
|
||||
Console.WriteLine($"FileSystemWatcher: Deleted - {fullPath}");
|
||||
}
|
||||
|
||||
private void HandleCreated(string fullPath)
|
||||
{
|
||||
Console.WriteLine($"FileSystemWatcher: Created - {fullPath}");
|
||||
}
|
||||
|
||||
// The only changed event we care about is files, not directories
|
||||
// We will naively assume that if the file name does not have an extension, it's a directory
|
||||
// This may not always be true, but it lets us avoid reading the file system to check
|
||||
// TODO: Make a note to users that they should not use files without extensions
|
||||
private void HandleChanged(string fullPath)
|
||||
{
|
||||
if (Path.HasExtension(fullPath) is false) return;
|
||||
// TODO: Handle updating the content of open files in editors
|
||||
Console.WriteLine($"FileSystemWatcher: Changed - {fullPath}");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
StopWatching();
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ public class SharpIdeSolutionModel : ISharpIdeNode, IExpandableSharpIdeNode
|
||||
{
|
||||
public required string Name { get; set; }
|
||||
public required string FilePath { get; set; }
|
||||
public required string DirectoryPath { get; set; }
|
||||
public required List<SharpIdeProjectModel> Projects { get; set; }
|
||||
public required List<SharpIdeSolutionFolder> Folders { get; set; }
|
||||
public required HashSet<SharpIdeProjectModel> AllProjects { get; set; }
|
||||
@@ -48,6 +49,7 @@ public class SharpIdeSolutionModel : ISharpIdeNode, IExpandableSharpIdeNode
|
||||
var allFiles = new ConcurrentBag<SharpIdeFile>();
|
||||
Name = solutionName;
|
||||
FilePath = solutionFilePath;
|
||||
DirectoryPath = Path.GetDirectoryName(solutionFilePath)!;
|
||||
Projects = intermediateModel.Projects.Select(s => new SharpIdeProjectModel(s, allProjects, allFiles, this)).ToList();
|
||||
Folders = intermediateModel.SolutionFolders.Select(s => new SharpIdeSolutionFolder(s, allProjects, allFiles, this)).ToList();
|
||||
AllProjects = allProjects.ToHashSet();
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CliWrap" />
|
||||
<PackageReference Include="FileWatcherEx" />
|
||||
<PackageReference Include="Microsoft.Diagnostics.NETCore.Client" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Shared.VSCodeDebugProtocol" />
|
||||
<!-- If any Microsoft.Build.*.dll (Excluding Locator) ends up in the output, it will be prioritised for loading by MSBuild Nodes -->
|
||||
<PackageReference Include="Ardalis.GuardClauses" />
|
||||
|
||||
@@ -4,6 +4,8 @@ using Microsoft.Extensions.Hosting;
|
||||
using SharpIDE.Application.Features.Analysis;
|
||||
using SharpIDE.Application.Features.Build;
|
||||
using SharpIDE.Application.Features.Events;
|
||||
using SharpIDE.Application.Features.FileWatching;
|
||||
using SharpIDE.Application.Features.Run;
|
||||
using SharpIDE.Application.Features.SolutionDiscovery;
|
||||
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||
using SharpIDE.Godot.Features.BottomPanel;
|
||||
@@ -39,6 +41,10 @@ public partial class IdeRoot : Control
|
||||
{
|
||||
GodotGlobalEvents.Instance = new GodotGlobalEvents();
|
||||
GlobalEvents.Instance = new GlobalEvents();
|
||||
Singletons.RunService = new RunService();
|
||||
Singletons.BuildService = new BuildService();
|
||||
Singletons.FileWatcher?.Dispose();
|
||||
Singletons.FileWatcher = new IdeFileWatcher();
|
||||
}
|
||||
|
||||
public override void _Ready()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SharpIDE.Application.Features.Build;
|
||||
using SharpIDE.Application.Features.FileWatching;
|
||||
using SharpIDE.Application.Features.Run;
|
||||
using SharpIDE.Godot.Features.IdeSettings;
|
||||
|
||||
@@ -6,7 +7,8 @@ namespace SharpIDE.Godot;
|
||||
|
||||
public static class Singletons
|
||||
{
|
||||
public static RunService RunService { get; } = new RunService();
|
||||
public static BuildService BuildService { get; } = new BuildService();
|
||||
public static RunService RunService { get; set; } = null!;
|
||||
public static BuildService BuildService { get; set; } = null!;
|
||||
public static IdeFileWatcher FileWatcher { get; set; } = null!;
|
||||
public static AppState AppState { get; set; } = null!;
|
||||
}
|
||||
Reference in New Issue
Block a user