From 02022599e5760c0221882c4e58ddd36ea113a866 Mon Sep 17 00:00:00 2001 From: goat Date: Fri, 7 Jun 2024 21:04:31 +0200 Subject: [PATCH] console: add public interface --- Dalamud/Console/ConsoleManager.cs | 4 +- Dalamud/Console/ConsoleManagerPluginScoped.cs | 174 ++++++++++++++++++ Dalamud/Plugin/Services/IConsole.cs | 130 +++++++++++++ 3 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 Dalamud/Console/ConsoleManagerPluginScoped.cs create mode 100644 Dalamud/Plugin/Services/IConsole.cs diff --git a/Dalamud/Console/ConsoleManager.cs b/Dalamud/Console/ConsoleManager.cs index c4c68e033..5ee2b6d72 100644 --- a/Dalamud/Console/ConsoleManager.cs +++ b/Dalamud/Console/ConsoleManager.cs @@ -191,7 +191,7 @@ internal partial class ConsoleManager : IServiceType return false; var entryName = matches[0].Value; - if (string.IsNullOrEmpty(entryName) || entryName.Any(x => x == ' ')) + if (string.IsNullOrEmpty(entryName) || entryName.Any(char.IsWhiteSpace)) { Log.Error("No valid command specified"); return false; @@ -419,7 +419,7 @@ internal partial class ConsoleManager : IServiceType /// private class ConsoleCommand : ConsoleEntry, IConsoleCommand { - private Delegate func; + private readonly Delegate func; /// /// Initializes a new instance of the class. diff --git a/Dalamud/Console/ConsoleManagerPluginScoped.cs b/Dalamud/Console/ConsoleManagerPluginScoped.cs new file mode 100644 index 000000000..3d11aca18 --- /dev/null +++ b/Dalamud/Console/ConsoleManagerPluginScoped.cs @@ -0,0 +1,174 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +using Dalamud.IoC; +using Dalamud.IoC.Internal; +using Dalamud.Plugin.Internal.Types; +using Dalamud.Plugin.Services; + +namespace Dalamud.Console; + +/// +/// Plugin-scoped version of the console service. +/// +[PluginInterface] +[InterfaceVersion("1.0")] +[ServiceManager.ScopedService] +#pragma warning disable SA1015 +[ResolveVia] +#pragma warning restore SA1015 +public class ConsoleManagerPluginScoped : IConsole, IInternalDisposableService +{ + private readonly ConsoleManager console; + + private readonly List trackedEntries = new(); + + /// + /// Initializes a new instance of the class. + /// + /// The plugin this service belongs to. + /// The console manager. + [ServiceManager.ServiceConstructor] + internal ConsoleManagerPluginScoped(LocalPlugin plugin, ConsoleManager console) + { + this.console = console; + + this.Prefix = ConsoleManagerPluginUtil.GetSanitizedNamespaceName(plugin.InternalName); + } + + /// + public string Prefix { get; private set; } + + /// + void IInternalDisposableService.DisposeService() + { + foreach (var trackedEntry in this.trackedEntries) + { + this.console.RemoveEntry(trackedEntry); + } + + this.trackedEntries.Clear(); + } + + /// + public IConsoleCommand AddCommand(string name, string description, Func func) + => this.InternalAddCommand(name, description, func); + + /// + public IConsoleCommand AddCommand(string name, string description, Func func) + => this.InternalAddCommand(name, description, func); + + /// + public IConsoleCommand AddCommand(string name, string description, Func func) + => this.InternalAddCommand(name, description, func); + + /// + public IConsoleCommand AddCommand(string name, string description, Func func) + => this.InternalAddCommand(name, description, func); + + /// + public IConsoleCommand AddCommand(string name, string description, Func func) + => this.InternalAddCommand(name, description, func); + + /// + public IConsoleCommand AddCommand(string name, string description, Func func) + => this.InternalAddCommand(name, description, func); + + /// + public IConsoleVariable AddVariable(string name, string description, T defaultValue) + { + var variable = this.console.AddVariable(this.GetPrefixedName(name), description, defaultValue); + this.trackedEntries.Add(variable); + return variable; + } + + /// + public IConsoleEntry AddAlias(string name, string alias) + { + var entry = this.console.AddAlias(this.GetPrefixedName(name), alias); + this.trackedEntries.Add(entry); + return entry; + } + + /// + public T GetVariable(string name) + { + return this.console.GetVariable(this.GetPrefixedName(name)); + } + + /// + public void SetVariable(string name, T value) + { + this.console.SetVariable(this.GetPrefixedName(name), value); + } + + /// + public void RemoveEntry(IConsoleEntry entry) + { + this.console.RemoveEntry(entry); + this.trackedEntries.Remove(entry); + } + + private string GetPrefixedName(string name) + { + ArgumentNullException.ThrowIfNull(name); + + // If the name is empty, return the prefix to allow for a single command or variable to be top-level. + if (name.Length == 0) + return this.Prefix; + + if (name.Any(char.IsWhiteSpace)) + throw new ArgumentException("Name cannot contain whitespace.", nameof(name)); + + return $"{this.Prefix}.{name}"; + } + + private IConsoleCommand InternalAddCommand(string name, string description, Delegate func) + { + var command = this.console.AddCommand(this.GetPrefixedName(name), description, func); + this.trackedEntries.Add(command); + return command; + } +} + +/// +/// Utility functions for the console manager. +/// +internal static partial class ConsoleManagerPluginUtil +{ + private static readonly string[] ReservedNamespaces = ["dalamud", "xl"]; + + /// + /// Get a sanitized namespace name from a plugin's internal name. + /// + /// The plugin's internal name. + /// A sanitized namespace. + public static string GetSanitizedNamespaceName(string pluginInternalName) + { + // Must be lowercase + pluginInternalName = pluginInternalName.ToLowerInvariant(); + + // Remove all non-alphabetic characters + pluginInternalName = NonAlphaRegex().Replace(pluginInternalName, string.Empty); + + // Remove reserved namespaces from the start or end + foreach (var reservedNamespace in ReservedNamespaces) + { + if (pluginInternalName.StartsWith(reservedNamespace)) + { + pluginInternalName = pluginInternalName[reservedNamespace.Length..]; + } + + if (pluginInternalName.EndsWith(reservedNamespace)) + { + pluginInternalName = pluginInternalName[..^reservedNamespace.Length]; + } + } + + return pluginInternalName; + } + + [GeneratedRegex(@"[^a-z]")] + private static partial Regex NonAlphaRegex(); +} diff --git a/Dalamud/Plugin/Services/IConsole.cs b/Dalamud/Plugin/Services/IConsole.cs new file mode 100644 index 000000000..0b6832efb --- /dev/null +++ b/Dalamud/Plugin/Services/IConsole.cs @@ -0,0 +1,130 @@ +using System.Diagnostics.CodeAnalysis; + +using Dalamud.Console; + +namespace Dalamud.Plugin.Services; + +/// +/// Provides functions to register console commands and variables. +/// +[Experimental("Dalamud001")] +public interface IConsole +{ + /// + /// Gets this plugin's namespace prefix, derived off its internal name. + /// This is the prefix that all commands and variables registered by this plugin will have. + /// If the internal name is "SamplePlugin", the prefix will be "sampleplugin.". + /// + public string Prefix { get; } + + /// + /// Add a command to the console. + /// + /// The name of the command. + /// A description of the command. + /// Function to invoke when the command has been called. Must return a indicating success. + /// The added command. + public IConsoleCommand AddCommand(string name, string description, Func func); + + /// + /// Add a command to the console. + /// + /// The name of the command. + /// A description of the command. + /// Function to invoke when the command has been called. Must return a indicating success. + /// The first argument to the command. + /// The added command. + public IConsoleCommand AddCommand(string name, string description, Func func); + + /// + /// Add a command to the console. + /// + /// The name of the command. + /// A description of the command. + /// Function to invoke when the command has been called. Must return a indicating success. + /// The first argument to the command. + /// The second argument to the command. + /// The added command. + public IConsoleCommand AddCommand(string name, string description, Func func); + + /// + /// Add a command to the console. + /// + /// The name of the command. + /// A description of the command. + /// Function to invoke when the command has been called. Must return a indicating success. + /// The first argument to the command. + /// The second argument to the command. + /// The third argument to the command. + /// The added command. + public IConsoleCommand AddCommand(string name, string description, Func func); + + /// + /// Add a command to the console. + /// + /// The name of the command. + /// A description of the command. + /// Function to invoke when the command has been called. Must return a indicating success. + /// The first argument to the command. + /// The second argument to the command. + /// The third argument to the command. + /// The fourth argument to the command. + /// The added command. + public IConsoleCommand AddCommand( + string name, string description, Func func); + + /// + /// Add a command to the console. + /// + /// The name of the command. + /// A description of the command. + /// Function to invoke when the command has been called. Must return a indicating success. + /// The first argument to the command. + /// The second argument to the command. + /// The third argument to the command. + /// The fourth argument to the command. + /// The fifth argument to the command. + /// The added command. + public IConsoleCommand AddCommand( + string name, string description, Func func); + + /// + /// Add a variable to the console. + /// + /// The name of the variable. + /// A description of the variable. + /// The default value of the variable. + /// The type of the variable. + /// The added variable. + public IConsoleVariable AddVariable(string name, string description, T defaultValue); + + /// + /// Add an alias to a console entry. + /// + /// The name of the entry to add an alias for. + /// The alias to use. + /// The added alias. + public IConsoleEntry AddAlias(string name, string alias); + + /// + /// Get the value of a variable. + /// + /// The name of the variable. + /// The type of the variable. + /// The value of the variable. + public T GetVariable(string name); + + /// + /// Set the value of a variable. + /// + /// The name of the variable. + /// The value to set. + /// The type of the value to set. + public void SetVariable(string name, T value); + + /// + /// Remove an entry from the console. + /// + /// The entry to remove. + public void RemoveEntry(IConsoleEntry entry); +}