Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Microsoft.Extensions.Options;

namespace SampSharp.Entities.SAMP.Commands;

/// <summary>
Expand All @@ -7,16 +9,20 @@ namespace SampSharp.Entities.SAMP.Commands;
internal class DefaultConsoleCommandMessageService : IConsoleCommandMessageService
{
private readonly ICommandTextFormatter _formatter;
private readonly ConsoleCommandServiceOptions _options;

/// <summary>
/// Initializes a new instance of the <see cref="DefaultConsoleCommandMessageService"/> class with the specified command text formatter.
/// </summary>
/// <param name="formatter">A formatter used to format command text.</param>
public DefaultConsoleCommandMessageService(ICommandTextFormatter formatter)
/// <param name="options">The command service options.</param>
public DefaultConsoleCommandMessageService(ICommandTextFormatter formatter, IOptions<ConsoleCommandServiceOptions> options)
{
ArgumentNullException.ThrowIfNull(formatter);
ArgumentNullException.ThrowIfNull(options);

_formatter = formatter;
_options = options.Value;
}

/// <inheritdoc />
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,12 @@ public class CommandServiceOptions
/// Defaults to <see cref="StringComparison.OrdinalIgnoreCase"/>.
/// </summary>
public StringComparison StringComparison { get; set; } = StringComparison.OrdinalIgnoreCase;

/// <summary>
/// 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:".
/// </summary>
public string UsageMessagePrefix { get; set; } = "Usage:";
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@ namespace SampSharp.Entities.SAMP.Commands;
/// </summary>
public class PlayerCommandServiceOptions : CommandServiceOptions
{
/// <summary>
/// Gets or sets the color used when displaying command usage messages.
/// Defaults to <see cref="Color.White"/>.
/// </summary>
public Color UsageMessageColor { get; set; } = Color.White;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Microsoft.Extensions.Options;

namespace SampSharp.Entities.SAMP.Commands;

/// <summary>
Expand All @@ -7,16 +9,20 @@ namespace SampSharp.Entities.SAMP.Commands;
public class DefaultPlayerCommandMessageService : IPlayerCommandMessageService
{
private readonly ICommandTextFormatter _formatter;
private readonly PlayerCommandServiceOptions _options;

/// <summary>
/// Initializes a new instance of the <see cref="DefaultPlayerCommandMessageService"/> class with the specified command text formatter.
/// </summary>
/// <param name="formatter">A formatter used to format command text.</param>
public DefaultPlayerCommandMessageService(ICommandTextFormatter formatter)
/// <param name="options">The command service options.</param>
public DefaultPlayerCommandMessageService(ICommandTextFormatter formatter, IOptions<PlayerCommandServiceOptions> options)
{
ArgumentNullException.ThrowIfNull(formatter);
ArgumentNullException.ThrowIfNull(options);

_formatter = formatter;
_options = options.Value;
}

/// <inheritdoc />
Expand Down Expand Up @@ -48,11 +54,11 @@ public virtual void SendUsage(Player player, IReadOnlyList<CommandDefinition> 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
Expand All @@ -78,7 +84,7 @@ public virtual void SendUsage(Player player, IReadOnlyList<CommandDefinition> ov

foreach (var message in messages)
{
player.SendClientMessage(message);
player.SendClientMessage(_options.UsageMessageColor, message);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Reflection;
using Microsoft.Extensions.Options;
using Moq;
using SampSharp.Entities;
using SampSharp.Entities.SAMP.Commands;
Expand Down Expand Up @@ -35,7 +36,7 @@ private void DummyMethod() { }
[Fact]
public void Constructor_NullFormatter_ThrowsArgumentNullException()
{
Should.Throw<ArgumentNullException>(() => new DefaultConsoleCommandMessageService(null!));
Should.Throw<ArgumentNullException>(() => new DefaultConsoleCommandMessageService(null!, null!));
}

[Fact]
Expand All @@ -44,10 +45,13 @@ public void SendUsage_SingleOverload_SendsFormattedMessage()
var messages = new List<string>();
var context = new ConsoleCommandDispatchContext(null, messages.Add);
var formatterMock = new Mock<ICommandTextFormatter>();
var optionsMock = new Mock<IOptions<ConsoleCommandServiceOptions>>();
formatterMock.Setup(f => f.FormatCommandUsage(It.IsAny<string>(), It.IsAny<string?>(), It.IsAny<CommandParameterInfo[]>(), It.IsAny<bool>()))
.Returns("test <amount>");
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 });
Expand All @@ -62,10 +66,13 @@ public void SendUsage_MultipleOverloads_SendsHeaderAndEachOverload()
var messages = new List<string>();
var context = new ConsoleCommandDispatchContext(null, messages.Add);
var formatterMock = new Mock<ICommandTextFormatter>();
var optionsMock = new Mock<IOptions<ConsoleCommandServiceOptions>>();
formatterMock.Setup(f => f.FormatCommandUsage(It.IsAny<string>(), It.IsAny<string?>(), It.IsAny<CommandParameterInfo[]>(), It.IsAny<bool>()))
.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");

Expand All @@ -82,11 +89,14 @@ public void SendUsage_WithUsedCommandName_UsesAliasName()
string? capturedName = null;
var context = new ConsoleCommandDispatchContext(null, _ => { });
var formatterMock = new Mock<ICommandTextFormatter>();
var optionsMock = new Mock<IOptions<ConsoleCommandServiceOptions>>();
formatterMock.Setup(f => f.FormatCommandUsage(It.IsAny<string>(), It.IsAny<string?>(), It.IsAny<CommandParameterInfo[]>(), It.IsAny<bool>()))
.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");
Expand All @@ -100,11 +110,14 @@ public void SendUsage_SingleOverload_DoesNotIncludeSlash()
bool? capturedIncludeSlash = null;
var context = new ConsoleCommandDispatchContext(null, _ => { });
var formatterMock = new Mock<ICommandTextFormatter>();
var optionsMock = new Mock<IOptions<ConsoleCommandServiceOptions>>();
formatterMock.Setup(f => f.FormatCommandUsage(It.IsAny<string>(), It.IsAny<string?>(), It.IsAny<CommandParameterInfo[]>(), It.IsAny<bool>()))
.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 });
Expand All @@ -117,10 +130,13 @@ public void SendUsage_ReturnsTrue()
{
var context = new ConsoleCommandDispatchContext(null, _ => { });
var formatterMock = new Mock<ICommandTextFormatter>();
var optionsMock = new Mock<IOptions<ConsoleCommandServiceOptions>>();
formatterMock.Setup(f => f.FormatCommandUsage(It.IsAny<string>(), It.IsAny<string?>(), It.IsAny<CommandParameterInfo[]>(), It.IsAny<bool>()))
.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 });
Expand Down
Loading