diff --git a/src/SharpIDE.Godot/DiAutoload.cs b/src/SharpIDE.Godot/DiAutoload.cs index 688fa7f..6b3dbd4 100644 --- a/src/SharpIDE.Godot/DiAutoload.cs +++ b/src/SharpIDE.Godot/DiAutoload.cs @@ -14,18 +14,19 @@ public class InjectAttribute : Attribute; public partial class DiAutoload : Node { private ServiceProvider? _serviceProvider; + private IServiceScope? _currentScope; public override void _EnterTree() { GD.Print("[Injector] _EnterTree called"); var services = new ServiceCollection(); // Register services here - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); _serviceProvider = services.BuildServiceProvider(); GetTree().NodeAdded += OnNodeAdded; @@ -37,6 +38,13 @@ public partial class DiAutoload : Node } + /// The solution has changed, so reset the scope to get new services + public void ResetScope() + { + _currentScope?.Dispose(); + _currentScope = _serviceProvider!.CreateScope(); + } + private void OnNodeAdded(Node node) { // Inject dependencies into every new node @@ -52,11 +60,18 @@ public partial class DiAutoload : Node { if (Attribute.IsDefined(field, typeof(InjectAttribute))) { - var service = _serviceProvider!.GetService(field.FieldType); + if (_currentScope is null) + { + GD.PrintErr("[Injector] _currentScope was null when attempting to resolve service"); + GetTree().Quit(); + return; + } + var service = _currentScope!.ServiceProvider.GetService(field.FieldType); if (service is null) { GD.PrintErr($"[Injector] No service registered for {field.FieldType}"); GetTree().Quit(); + return; } field.SetValue(target, service); diff --git a/src/SharpIDE.Godot/Features/BottomPanel/BottomPanelManager.cs b/src/SharpIDE.Godot/Features/BottomPanel/BottomPanelManager.cs index b81d947..bab123b 100644 --- a/src/SharpIDE.Godot/Features/BottomPanel/BottomPanelManager.cs +++ b/src/SharpIDE.Godot/Features/BottomPanel/BottomPanelManager.cs @@ -1,7 +1,10 @@ using Godot; using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence; +using SharpIDE.Godot.Features.Build; +using SharpIDE.Godot.Features.Debug_; using SharpIDE.Godot.Features.IdeDiagnostics; using SharpIDE.Godot.Features.Problems; +using SharpIDE.Godot.Features.Run; namespace SharpIDE.Godot.Features.BottomPanel; @@ -17,9 +20,9 @@ public partial class BottomPanelManager : Panel } } - private Control _runPanel = null!; - private Control _debugPanel = null!; - private Control _buildPanel = null!; + private RunPanel _runPanel = null!; + private DebugPanel _debugPanel = null!; + private BuildPanel _buildPanel = null!; private ProblemsPanel _problemsPanel = null!; private IdeDiagnosticsPanel _ideDiagnosticsPanel = null!; @@ -27,9 +30,9 @@ public partial class BottomPanelManager : Panel public override void _Ready() { - _runPanel = GetNode("%RunPanel"); - _debugPanel = GetNode("%DebugPanel"); - _buildPanel = GetNode("%BuildPanel"); + _runPanel = GetNode("%RunPanel"); + _debugPanel = GetNode("%DebugPanel"); + _buildPanel = GetNode("%BuildPanel"); _problemsPanel = GetNode("%ProblemsPanel"); _ideDiagnosticsPanel = GetNode("%IdeDiagnosticsPanel"); diff --git a/src/SharpIDE.Godot/IdeRoot.cs b/src/SharpIDE.Godot/IdeRoot.cs index 6f94ae8..165a6a6 100644 --- a/src/SharpIDE.Godot/IdeRoot.cs +++ b/src/SharpIDE.Godot/IdeRoot.cs @@ -42,6 +42,7 @@ public partial class IdeRoot : Control [Inject] private readonly IdeFileExternalChangeHandler _fileExternalChangeHandler = null!; [Inject] private readonly IdeFileWatcher _fileWatcher = null!; [Inject] private readonly BuildService _buildService = null!; + [Inject] private readonly IdeOpenTabsFileManager _openTabsFileManager = null!; public override void _EnterTree() { @@ -52,7 +53,8 @@ public partial class IdeRoot : Control public override void _ExitTree() { - _fileWatcher.Dispose(); + _fileWatcher?.Dispose(); + GetTree().GetRoot().FocusExited -= OnFocusExited; } public override void _Ready() @@ -80,8 +82,15 @@ public partial class IdeRoot : Control _cleanSlnButton.Pressed += OnCleanSlnButtonPressed; _restoreSlnButton.Pressed += OnRestoreSlnButtonPressed; GodotGlobalEvents.Instance.BottomPanelVisibilityChangeRequested.Subscribe(async show => await this.InvokeAsync(() => _invertedVSplitContainer.InvertedSetCollapsed(!show))); + GetTree().GetRoot().FocusExited += OnFocusExited; _nodeReadyTcs.SetResult(); } + + // TODO: Problematic, as this is called even when the focus shifts to an embedded subwindow, such as a popup + private void OnFocusExited() + { + _ = Task.GodotRun(async () => await _openTabsFileManager.SaveAllOpenFilesAsync()); + } private void OnRunMenuButtonPressed() { diff --git a/src/SharpIDE.Godot/IdeWindow.cs b/src/SharpIDE.Godot/IdeWindow.cs index 8ea9174..4ce0c9d 100644 --- a/src/SharpIDE.Godot/IdeWindow.cs +++ b/src/SharpIDE.Godot/IdeWindow.cs @@ -21,8 +21,6 @@ public partial class IdeWindow : Control private IdeRoot? _ideRoot; private SlnPicker? _slnPicker; - [Inject] private readonly IdeOpenTabsFileManager _openTabsFileManager = null!; - public override void _Ready() { GD.Print("IdeWindow _Ready called"); @@ -31,7 +29,6 @@ public partial class IdeWindow : Control MSBuildLocator.RegisterDefaults(); GodotServiceDefaults.AddServiceDefaults(); Singletons.AppState = AppStateLoader.LoadAppStateFromConfigFile(); - GetWindow().FocusExited += OnFocusExited; //GetWindow().SetMinSize(new Vector2I(1152, 648)); Callable.From(() => PickSolution(true)).CallDeferred(); } @@ -47,12 +44,6 @@ public partial class IdeWindow : Control // PrintOrphanNodes(); } - // TODO: Problematic, as this is called even when the focus shifts to an embedded subwindow, such as a popup - private void OnFocusExited() - { - _ = Task.GodotRun(async () => await _openTabsFileManager.SaveAllOpenFilesAsync()); - } - public void PickSolution(bool fullscreen = false) { if (_slnPicker is not null) throw new InvalidOperationException("Solution picker is already active"); @@ -109,7 +100,8 @@ public partial class IdeWindow : Control { GetWindow().Mode = Window.ModeEnum.Maximized; } - _ideRoot = ideRoot; + _ideRoot = ideRoot; // This has no DI services, until it is added to the scene tree + GetNode("/root/DiAutoload").ResetScope(); AddChild(ideRoot); }); });