diff --git a/src/SampSharp.OpenMp.Entities.Commands/Console/DefaultConsoleCommandMessageService.cs b/src/SampSharp.OpenMp.Entities.Commands/Console/DefaultConsoleCommandMessageService.cs
index 150d6843..88902372 100644
--- a/src/SampSharp.OpenMp.Entities.Commands/Console/DefaultConsoleCommandMessageService.cs
+++ b/src/SampSharp.OpenMp.Entities.Commands/Console/DefaultConsoleCommandMessageService.cs
@@ -1,3 +1,5 @@
+using Microsoft.Extensions.Options;
+
namespace SampSharp.Entities.SAMP.Commands;
///
@@ -7,16 +9,20 @@ namespace SampSharp.Entities.SAMP.Commands;
internal class DefaultConsoleCommandMessageService : IConsoleCommandMessageService
{
private readonly ICommandTextFormatter _formatter;
+ private readonly ConsoleCommandServiceOptions _options;
///
/// Initializes a new instance of the class with the specified command text formatter.
///
/// A formatter used to format command text.
- public DefaultConsoleCommandMessageService(ICommandTextFormatter formatter)
+ /// The command service options.
+ public DefaultConsoleCommandMessageService(ICommandTextFormatter formatter, IOptions options)
{
ArgumentNullException.ThrowIfNull(formatter);
+ ArgumentNullException.ThrowIfNull(options);
_formatter = formatter;
+ _options = options.Value;
}
///
@@ -43,11 +49,11 @@ public virtual bool SendUsage(ConsoleCommandDispatchContext context, IReadOnlyLi
var text = _formatter.FormatCommandUsage(commandName, group, overload.ParsedParameters, includeSlash: false);
- context.SendMessage($"Usage: {text}");
+ context.SendMessage($"{_options.UsageMessagePrefix} {text}");
}
else
{
- context.SendMessage("Usage:");
+ context.SendMessage(_options.UsageMessagePrefix);
foreach (var overload in overloads)
{
// If usedCommandName is provided (e.g., an alias), use it as the complete path without the group
diff --git a/src/SampSharp.OpenMp.Entities.Commands/Options/CommandServiceOptions.cs b/src/SampSharp.OpenMp.Entities.Commands/Options/CommandServiceOptions.cs
index 4dab3537..a400f9a2 100644
--- a/src/SampSharp.OpenMp.Entities.Commands/Options/CommandServiceOptions.cs
+++ b/src/SampSharp.OpenMp.Entities.Commands/Options/CommandServiceOptions.cs
@@ -10,4 +10,12 @@ public class CommandServiceOptions
/// Defaults to .
///
public StringComparison StringComparison { get; set; } = StringComparison.OrdinalIgnoreCase;
+
+ ///
+ /// Gets or sets the prefix displayed before a command usage message.
+ /// For example, when set to "Syntax:", a usage message may be displayed as:
+ /// "Syntax: /pm [targetId] [reason]".
+ /// Defaults to "Usage:".
+ ///
+ public string UsageMessagePrefix { get; set; } = "Usage:";
}
\ No newline at end of file
diff --git a/src/SampSharp.OpenMp.Entities.Commands/Options/PlayerCommandServiceOptions.cs b/src/SampSharp.OpenMp.Entities.Commands/Options/PlayerCommandServiceOptions.cs
index aded42f4..41941880 100644
--- a/src/SampSharp.OpenMp.Entities.Commands/Options/PlayerCommandServiceOptions.cs
+++ b/src/SampSharp.OpenMp.Entities.Commands/Options/PlayerCommandServiceOptions.cs
@@ -5,4 +5,9 @@ namespace SampSharp.Entities.SAMP.Commands;
///
public class PlayerCommandServiceOptions : CommandServiceOptions
{
+ ///
+ /// Gets or sets the color used when displaying command usage messages.
+ /// Defaults to .
+ ///
+ public Color UsageMessageColor { get; set; } = Color.White;
}
\ No newline at end of file
diff --git a/src/SampSharp.OpenMp.Entities.Commands/Player/DefaultPlayerCommandMessageService.cs b/src/SampSharp.OpenMp.Entities.Commands/Player/DefaultPlayerCommandMessageService.cs
index 9e1bf5ad..43753e79 100644
--- a/src/SampSharp.OpenMp.Entities.Commands/Player/DefaultPlayerCommandMessageService.cs
+++ b/src/SampSharp.OpenMp.Entities.Commands/Player/DefaultPlayerCommandMessageService.cs
@@ -1,3 +1,5 @@
+using Microsoft.Extensions.Options;
+
namespace SampSharp.Entities.SAMP.Commands;
///
@@ -7,16 +9,20 @@ namespace SampSharp.Entities.SAMP.Commands;
public class DefaultPlayerCommandMessageService : IPlayerCommandMessageService
{
private readonly ICommandTextFormatter _formatter;
+ private readonly PlayerCommandServiceOptions _options;
///
/// Initializes a new instance of the class with the specified command text formatter.
///
/// A formatter used to format command text.
- public DefaultPlayerCommandMessageService(ICommandTextFormatter formatter)
+ /// The command service options.
+ public DefaultPlayerCommandMessageService(ICommandTextFormatter formatter, IOptions options)
{
ArgumentNullException.ThrowIfNull(formatter);
+ ArgumentNullException.ThrowIfNull(options);
_formatter = formatter;
+ _options = options.Value;
}
///
@@ -48,11 +54,11 @@ public virtual void SendUsage(Player player, IReadOnlyList ov
}
var text = _formatter.FormatCommandUsage(commandName, group, overload.ParsedParameters, includeSlash: true);
- messages.Add($"Usage: {text}");
+ messages.Add($"{_options.UsageMessagePrefix} {text}");
}
else
{
- messages.Add("Usage:");
+ messages.Add(_options.UsageMessagePrefix);
foreach (var overload in overloads)
{
// If usedCommandName is provided (e.g., an alias), use it as the complete path without the group
@@ -78,7 +84,7 @@ public virtual void SendUsage(Player player, IReadOnlyList ov
foreach (var message in messages)
{
- player.SendClientMessage(message);
+ player.SendClientMessage(_options.UsageMessageColor, message);
}
}
diff --git a/test/SampSharp.OpenMp.Entities.Commands.Tests/Console/DefaultConsoleCommandMessageServiceTests.cs b/test/SampSharp.OpenMp.Entities.Commands.Tests/Console/DefaultConsoleCommandMessageServiceTests.cs
index cd331c46..c83d2a30 100644
--- a/test/SampSharp.OpenMp.Entities.Commands.Tests/Console/DefaultConsoleCommandMessageServiceTests.cs
+++ b/test/SampSharp.OpenMp.Entities.Commands.Tests/Console/DefaultConsoleCommandMessageServiceTests.cs
@@ -1,4 +1,5 @@
using System.Reflection;
+using Microsoft.Extensions.Options;
using Moq;
using SampSharp.Entities;
using SampSharp.Entities.SAMP.Commands;
@@ -35,7 +36,7 @@ private void DummyMethod() { }
[Fact]
public void Constructor_NullFormatter_ThrowsArgumentNullException()
{
- Should.Throw(() => new DefaultConsoleCommandMessageService(null!));
+ Should.Throw(() => new DefaultConsoleCommandMessageService(null!, null!));
}
[Fact]
@@ -44,10 +45,13 @@ public void SendUsage_SingleOverload_SendsFormattedMessage()
var messages = new List();
var context = new ConsoleCommandDispatchContext(null, messages.Add);
var formatterMock = new Mock();
+ var optionsMock = new Mock>();
formatterMock.Setup(f => f.FormatCommandUsage(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
.Returns("test ");
+ optionsMock.Setup(f => f.Value)
+ .Returns(new ConsoleCommandServiceOptions());
- var service = new DefaultConsoleCommandMessageService(formatterMock.Object);
+ var service = new DefaultConsoleCommandMessageService(formatterMock.Object, optionsMock.Object);
var overload = CreateDefinition("test");
service.SendUsage(context, new[] { overload });
@@ -62,10 +66,13 @@ public void SendUsage_MultipleOverloads_SendsHeaderAndEachOverload()
var messages = new List();
var context = new ConsoleCommandDispatchContext(null, messages.Add);
var formatterMock = new Mock();
+ var optionsMock = new Mock>();
formatterMock.Setup(f => f.FormatCommandUsage(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
.Returns("formatted");
+ optionsMock.Setup(f => f.Value)
+ .Returns(new ConsoleCommandServiceOptions());
- var service = new DefaultConsoleCommandMessageService(formatterMock.Object);
+ var service = new DefaultConsoleCommandMessageService(formatterMock.Object, optionsMock.Object);
var overload1 = CreateDefinition("test");
var overload2 = CreateDefinition("test");
@@ -82,11 +89,14 @@ public void SendUsage_WithUsedCommandName_UsesAliasName()
string? capturedName = null;
var context = new ConsoleCommandDispatchContext(null, _ => { });
var formatterMock = new Mock();
+ var optionsMock = new Mock>();
formatterMock.Setup(f => f.FormatCommandUsage(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
.Callback((string name, string? group, CommandParameterInfo[] _, bool _) => capturedName = name)
.Returns("formatted");
+ optionsMock.Setup(f => f.Value)
+ .Returns(new ConsoleCommandServiceOptions());
- var service = new DefaultConsoleCommandMessageService(formatterMock.Object);
+ var service = new DefaultConsoleCommandMessageService(formatterMock.Object, optionsMock.Object);
var overload = CreateDefinition("message");
service.SendUsage(context, new[] { overload }, usedCommandName: "pm");
@@ -100,11 +110,14 @@ public void SendUsage_SingleOverload_DoesNotIncludeSlash()
bool? capturedIncludeSlash = null;
var context = new ConsoleCommandDispatchContext(null, _ => { });
var formatterMock = new Mock();
+ var optionsMock = new Mock>();
formatterMock.Setup(f => f.FormatCommandUsage(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
.Callback((string _, string? _, CommandParameterInfo[] _, bool includeSlash) => capturedIncludeSlash = includeSlash)
.Returns("formatted");
+ optionsMock.Setup(f => f.Value)
+ .Returns(new ConsoleCommandServiceOptions());
- var service = new DefaultConsoleCommandMessageService(formatterMock.Object);
+ var service = new DefaultConsoleCommandMessageService(formatterMock.Object, optionsMock.Object);
var overload = CreateDefinition("test");
service.SendUsage(context, new[] { overload });
@@ -117,10 +130,13 @@ public void SendUsage_ReturnsTrue()
{
var context = new ConsoleCommandDispatchContext(null, _ => { });
var formatterMock = new Mock();
+ var optionsMock = new Mock>();
formatterMock.Setup(f => f.FormatCommandUsage(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
.Returns("formatted");
+ optionsMock.Setup(f => f.Value)
+ .Returns(new ConsoleCommandServiceOptions());
- var service = new DefaultConsoleCommandMessageService(formatterMock.Object);
+ var service = new DefaultConsoleCommandMessageService(formatterMock.Object, optionsMock.Object);
var overload = CreateDefinition("test");
var result = service.SendUsage(context, new[] { overload });