Skip to content

Commit

Permalink
Basic store structure
Browse files Browse the repository at this point in the history
  • Loading branch information
dalyIsaac committed May 12, 2024
1 parent 19cf769 commit 3b898fc
Show file tree
Hide file tree
Showing 12 changed files with 474 additions and 145 deletions.
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="DotNext" Version="4.15.2" />
<PackageVersion Include="Markdig" Version="0.33.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Scripting" Version="4.8.0" />
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="7.0.0" />
Expand Down
296 changes: 151 additions & 145 deletions src/Whim/Context/Context.cs
Original file line number Diff line number Diff line change
@@ -1,145 +1,151 @@
using System;

namespace Whim;

/// <summary>
/// Implementation of <see cref="IContext"/>. This is the core of Whim. <br/>
///
/// <c>Context</c> consists of managers which contain and control Whim's state, and thus
/// functionality. <br/>
///
/// <c>Context</c> also contains other associated state and functionality, like the
/// <see cref="Logger"/>.
/// </summary>
internal class Context : IContext
{
private readonly IInternalContext _internalContext;
public IButler Butler { get; }
public IFileManager FileManager { get; }
public IResourceManager ResourceManager { get; }
public Logger Logger { get; }
public UncaughtExceptionHandling UncaughtExceptionHandling { get; set; } = UncaughtExceptionHandling.Log;
public INativeManager NativeManager { get; }
public IWorkspaceManager WorkspaceManager { get; }
public IWindowManager WindowManager { get; }
public IMonitorManager MonitorManager { get; }
public IRouterManager RouterManager { get; }
public IFilterManager FilterManager { get; }
private readonly CommandManager _commandManager;
public ICommandManager CommandManager => _commandManager;
public IPluginManager PluginManager { get; }
public IKeybindManager KeybindManager { get; }
public INotificationManager NotificationManager { get; }

public event EventHandler<ExitEventArgs>? Exiting;
public event EventHandler<ExitEventArgs>? Exited;

/// <summary>
/// Create a new <see cref="IContext"/>.
/// </summary>
public Context()
{
string[] args = Environment.GetCommandLineArgs();

FileManager = new FileManager(args);
Logger = new Logger();
ResourceManager = new ResourceManager();
_internalContext = new InternalContext(this);
Butler = new Butler(this, _internalContext);

NativeManager = new NativeManager(this, _internalContext);

RouterManager = new RouterManager(this);
FilterManager = new FilterManager();
WindowManager = new WindowManager(this, _internalContext);
MonitorManager = new MonitorManager(this, _internalContext);
WorkspaceManager = new WorkspaceManager(this, _internalContext);
_commandManager = new CommandManager();
PluginManager = new PluginManager(this, _commandManager);
KeybindManager = new KeybindManager(this);
NotificationManager = new NotificationManager(this);
}

public void Initialize()
{
// Load the core commands
CoreCommands coreCommands = new(this);

foreach (ICommand command in coreCommands.Commands)
{
_commandManager.AddPluginCommand(command);
}

foreach ((string name, IKeybind keybind) in coreCommands.Keybinds)
{
KeybindManager.SetKeybind(name, keybind);
}

DefaultFilteredWindows.LoadWindowsIgnoredByWhim(FilterManager);

// Initialize before ResourceManager so user dicts take precedence over the default dict.
ResourceManager.Initialize();

// Load the user's config.
ConfigLoader configLoader = new(FileManager);
DoConfig doConfig = configLoader.LoadConfig();
doConfig(this);

// Initialize the logger first.
Logger.Initialize(FileManager);

// Initialize the managers.
Logger.Debug("Initializing...");
_internalContext.PreInitialize();
PluginManager.PreInitialize();

NotificationManager.Initialize();
MonitorManager.Initialize();
WindowManager.Initialize();
WorkspaceManager.Initialize();

Butler.Initialize();

WindowManager.PostInitialize();
PluginManager.PostInitialize();
_internalContext.PostInitialize();

Logger.Debug("Completed initialization");
}

public void HandleUncaughtException(string procName, Exception exception)
{
Logger.Fatal($"Unhandled exception in {procName}: {exception}");

switch (UncaughtExceptionHandling)
{
case UncaughtExceptionHandling.Shutdown:
Exit(new ExitEventArgs() { Reason = ExitReason.Error, Message = exception.ToString() });
break;

case UncaughtExceptionHandling.Log:
default:
break;
}
}

public void Exit(ExitEventArgs? args = null)
{
Logger.Debug("Exiting context...");
args ??= new ExitEventArgs() { Reason = ExitReason.User };

Exiting?.Invoke(this, args);

PluginManager.Dispose();
WorkspaceManager.Dispose();
WindowManager.Dispose();
MonitorManager.Dispose();
NotificationManager.Dispose();
_internalContext.Dispose();

Logger.Debug("Mostly exited...");

Logger.Dispose();
Exited?.Invoke(this, args);
}
}
using System;

namespace Whim;

/// <summary>
/// Implementation of <see cref="IContext"/>. This is the core of Whim. <br/>
///
/// <c>Context</c> consists of managers which contain and control Whim's state, and thus
/// functionality. <br/>
///
/// <c>Context</c> also contains other associated state and functionality, like the
/// <see cref="Logger"/>.
/// </summary>
internal class Context : IContext
{
private readonly IInternalContext _internalContext;
public IButler Butler { get; }
public IFileManager FileManager { get; }
public IResourceManager ResourceManager { get; }
public Logger Logger { get; }
public UncaughtExceptionHandling UncaughtExceptionHandling { get; set; } = UncaughtExceptionHandling.Log;
public INativeManager NativeManager { get; }
public IWorkspaceManager WorkspaceManager { get; }
public IWindowManager WindowManager { get; }
public IMonitorManager MonitorManager { get; }
public IRouterManager RouterManager { get; }
public IFilterManager FilterManager { get; }

Check warning on line 27 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L17-L27

Added lines #L17 - L27 were not covered by tests
private readonly CommandManager _commandManager;
public ICommandManager CommandManager => _commandManager;
public IPluginManager PluginManager { get; }
public IKeybindManager KeybindManager { get; }
public INotificationManager NotificationManager { get; }

Check warning on line 32 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L29-L32

Added lines #L29 - L32 were not covered by tests

public IStore Store { get; }

Check warning on line 34 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L34

Added line #L34 was not covered by tests

public event EventHandler<ExitEventArgs>? Exiting;
public event EventHandler<ExitEventArgs>? Exited;

/// <summary>
/// Create a new <see cref="IContext"/>.
/// </summary>
public Context()
{
string[] args = Environment.GetCommandLineArgs();

Check warning on line 44 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L42-L44

Added lines #L42 - L44 were not covered by tests

FileManager = new FileManager(args);
Logger = new Logger();
ResourceManager = new ResourceManager();
_internalContext = new InternalContext(this);

Check warning on line 49 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L46-L49

Added lines #L46 - L49 were not covered by tests

Store = new Store(this, _internalContext);
Butler = new Butler(this, _internalContext);

Check warning on line 52 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L51-L52

Added lines #L51 - L52 were not covered by tests

NativeManager = new NativeManager(this, _internalContext);

Check warning on line 54 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L54

Added line #L54 was not covered by tests

RouterManager = new RouterManager(this);
FilterManager = new FilterManager();
WindowManager = new WindowManager(this, _internalContext);
MonitorManager = new MonitorManager(this, _internalContext);
WorkspaceManager = new WorkspaceManager(this, _internalContext);
_commandManager = new CommandManager();
PluginManager = new PluginManager(this, _commandManager);
KeybindManager = new KeybindManager(this);
NotificationManager = new NotificationManager(this);
}

Check warning on line 65 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L56-L65

Added lines #L56 - L65 were not covered by tests

public void Initialize()
{

Check warning on line 68 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L68

Added line #L68 was not covered by tests
// Load the core commands
CoreCommands coreCommands = new(this);

Check warning on line 70 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L70

Added line #L70 was not covered by tests

foreach (ICommand command in coreCommands.Commands)
{
_commandManager.AddPluginCommand(command);
}

Check warning on line 75 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L73-L75

Added lines #L73 - L75 were not covered by tests

foreach ((string name, IKeybind keybind) in coreCommands.Keybinds)
{
KeybindManager.SetKeybind(name, keybind);
}

Check warning on line 80 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L78-L80

Added lines #L78 - L80 were not covered by tests

DefaultFilteredWindows.LoadWindowsIgnoredByWhim(FilterManager);

Check warning on line 82 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L82

Added line #L82 was not covered by tests

// Initialize before ResourceManager so user dicts take precedence over the default dict.
ResourceManager.Initialize();

Check warning on line 85 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L85

Added line #L85 was not covered by tests

// Load the user's config.
ConfigLoader configLoader = new(FileManager);
DoConfig doConfig = configLoader.LoadConfig();
doConfig(this);

Check warning on line 90 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L88-L90

Added lines #L88 - L90 were not covered by tests

// Initialize the logger first.
Logger.Initialize(FileManager);

Check warning on line 93 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L93

Added line #L93 was not covered by tests

// Initialize the managers.
Logger.Debug("Initializing...");
_internalContext.PreInitialize();
Store.Initialize();
PluginManager.PreInitialize();

Check warning on line 99 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L96-L99

Added lines #L96 - L99 were not covered by tests

NotificationManager.Initialize();
MonitorManager.Initialize();
WindowManager.Initialize();
WorkspaceManager.Initialize();

Check warning on line 104 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L101-L104

Added lines #L101 - L104 were not covered by tests

Butler.Initialize();

Check warning on line 106 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L106

Added line #L106 was not covered by tests

WindowManager.PostInitialize();
PluginManager.PostInitialize();
_internalContext.PostInitialize();

Check warning on line 110 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L108-L110

Added lines #L108 - L110 were not covered by tests

Logger.Debug("Completed initialization");
}

Check warning on line 113 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L112-L113

Added lines #L112 - L113 were not covered by tests

public void HandleUncaughtException(string procName, Exception exception)
{
Logger.Fatal($"Unhandled exception in {procName}: {exception}");

Check warning on line 117 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L116-L117

Added lines #L116 - L117 were not covered by tests

switch (UncaughtExceptionHandling)
{
case UncaughtExceptionHandling.Shutdown:
Exit(new ExitEventArgs() { Reason = ExitReason.Error, Message = exception.ToString() });
break;

Check warning on line 123 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L122-L123

Added lines #L122 - L123 were not covered by tests

case UncaughtExceptionHandling.Log:
default:
break;

Check warning on line 127 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L127

Added line #L127 was not covered by tests
}
}

Check warning on line 129 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L129

Added line #L129 was not covered by tests

public void Exit(ExitEventArgs? args = null)
{
Logger.Debug("Exiting context...");

Check warning on line 133 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L132-L133

Added lines #L132 - L133 were not covered by tests
args ??= new ExitEventArgs() { Reason = ExitReason.User };

Exiting?.Invoke(this, args);

PluginManager.Dispose();
WorkspaceManager.Dispose();
WindowManager.Dispose();
MonitorManager.Dispose();
NotificationManager.Dispose();
Store.Dispose();
_internalContext.Dispose();

Check warning on line 144 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L138-L144

Added lines #L138 - L144 were not covered by tests

Logger.Debug("Mostly exited...");

Check warning on line 146 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L146

Added line #L146 was not covered by tests

Logger.Dispose();

Check warning on line 148 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L148

Added line #L148 was not covered by tests
Exited?.Invoke(this, args);
}

Check warning on line 150 in src/Whim/Context/Context.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Context/Context.cs#L150

Added line #L150 was not covered by tests
}
51 changes: 51 additions & 0 deletions src/Whim/Store/IStore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using DotNext;

namespace Whim;

/// <summary>
/// Whim's store.
/// </summary>
public interface IStore : IDisposable
{
/// <summary>
/// Initialize the event listeners.
/// </summary>
public void Initialize();

/// <summary>
/// Dispatch updates to transform Whim's state.
/// </summary>
/// <typeparam name="TResult">
/// The result from the transform, if it's successful.
/// </typeparam>
/// <param name="transform">
/// The record implementing <see cref="Dispatch"/> to update Whim's state.
/// </param>
/// <returns></returns>
public Result<TResult> Dispatch<TResult>(Transform<TResult> transform);

/// <summary>
/// Entry-point to pick from Whim's state.
/// </summary>
/// <typeparam name="TResult">
/// The type of the resulting data from the store.
/// </typeparam>
/// <param name="picker">
/// The record implementing <see cref="Picker{TResult}"/> to fetch from Whim's state.
/// </param>
/// <returns></returns>
public TResult Pick<TResult>(Picker<TResult> picker);

/// <summary>
/// Entry-point to pick from Whim's state.
/// </summary>
/// <typeparam name="TResult">
/// The type of the resulting data from the store.
/// </typeparam>
/// <param name="picker">
/// Pure picker to fetch from Whim's state.
/// </param>
/// <returns></returns>
public TResult Pick<TResult>(PurePicker<TResult> picker);
}
27 changes: 27 additions & 0 deletions src/Whim/Store/Picker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Whim;

/// <summary>
/// Description of how to retrieve data from the <see cref="Store"/>.
/// The implementing record should be populated with the payload.
/// </summary>
/// <typeparam name="TResult">The type of the resulting data from the store.</typeparam>
public abstract record Picker<TResult>()
{

Check warning on line 9 in src/Whim/Store/Picker.cs

View check run for this annotation

Codecov / codecov/patch

src/Whim/Store/Picker.cs#L8-L9

Added lines #L8 - L9 were not covered by tests
/// <summary>
/// How to fetch the data from the store.
/// </summary>
/// <param name="ctx">Whim's context.</param>
/// <param name="internalCtx">Internal-only parts of Whim's API.</param>
/// <param name="rootSector"></param>
/// <returns></returns>
internal abstract TResult Execute(IContext ctx, IInternalContext internalCtx, IRootSector rootSector);
}

/// <summary>
/// Description of how to retrieve data from the <see cref="Store"/>.
/// Pure pickers can be implemented in terms of pure functions.
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="rootSector"></param>
/// <returns></returns>
public delegate TResult PurePicker<TResult>(IRootSector rootSector);
6 changes: 6 additions & 0 deletions src/Whim/Store/RootSector/IRootSector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Whim;

/// <summary>
/// The root sector of the state. This is read-only.
/// </summary>
public interface IRootSector { }
Loading

0 comments on commit 3b898fc

Please sign in to comment.