Skip to content
Open
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -364,4 +364,7 @@ FodyWeavers.xsd

# Settings file
appsettings.json
!Documentation/**/appsettings.json
!Documentation/**/appsettings.json

# Intellij configuration files (eg. Jetbrains Rider)
.idea/
2 changes: 1 addition & 1 deletion NetCord.Services/UserId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public UserId(ulong id, User? user) : this(id)
User = user;
}

public override string ToString() => $"<@{Id}>";
public override string ToString() => Mention.User(Id);

public override bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null) => Mention.TryFormatUser(destination, out charsWritten, Id);
}
2 changes: 1 addition & 1 deletion NetCord/Channels/Channel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public abstract partial class Channel(JsonChannel jsonModel, RestClient client)

Permissions IInteractionChannel.Permissions => _jsonModel.Permissions.GetValueOrDefault();

public override string ToString() => $"<#{Id}>";
public override string ToString() => Mention.Channel(Id);

public override bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null) => Mention.TryFormatChannel(destination, out charsWritten, Id);

Expand Down
144 changes: 112 additions & 32 deletions NetCord/Mention.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,165 @@ namespace NetCord;

public static class Mention
{
public static bool TryParseUser(ReadOnlySpan<char> mention, out ulong id)
public static string User(ulong userId) => $"<@{userId}>";

public static bool TryFormatUser(Span<char> destination, out int charsWritten, ulong userId)
{
return TryFormat(destination, out charsWritten, userId, "<@", ">");
}

public static bool TryParseUser(ReadOnlySpan<char> mention, out ulong userId)
{
if (mention is ['<', '@', _, .., '>'])
{
mention = mention[2] is '!' ? mention[3..^1] : mention[2..^1];

if (Snowflake.TryParse(mention, out id))
if (Snowflake.TryParse(mention, out userId))
return true;
}
else
id = default;
userId = default;

return false;
}

public static ulong ParseUser(ReadOnlySpan<char> mention)
public static ulong ParseUser(ReadOnlySpan<char> userMention)
{
if (TryParseUser(mention, out ulong id))
if (TryParseUser(userMention, out ulong id))
return id;
else
throw new FormatException("Cannot parse the mention.");
}

public static bool TryParseChannel(ReadOnlySpan<char> mention, out ulong id)
public static string Channel(ulong channelId) => $"<#{channelId}>";

public static bool TryFormatChannel(Span<char> destination, out int charsWritten, ulong channelId)
{
return TryFormat(destination, out charsWritten, channelId, "<#", ">");
}

public static bool TryParseChannel(ReadOnlySpan<char> mention, out ulong channelId)
{
if (mention is ['<', '#', .., '>'])
{
if (Snowflake.TryParse(mention[2..^1], out id))
if (Snowflake.TryParse(mention[2..^1], out channelId))
return true;
}
else
id = default;
channelId = default;

return false;
}

public static ulong ParseChannel(ReadOnlySpan<char> mention)
public static ulong ParseChannel(ReadOnlySpan<char> channelMention)
{
if (TryParseChannel(mention, out ulong id))
if (TryParseChannel(channelMention, out ulong id))
return id;
else
throw new FormatException("Cannot parse the mention.");
}

public static bool TryParseRole(ReadOnlySpan<char> mention, out ulong id)
public static string Role(ulong roleId) => $"<@&{roleId}>";

public static bool TryFormatRole(Span<char> destination, out int charsWritten, ulong roleId)
{
return TryFormat(destination, out charsWritten, roleId, "<@&", ">");
}

public static bool TryParseRole(ReadOnlySpan<char> mention, out ulong roleId)
{
if (mention is ['<', '@', '&', .., '>'])
{
if (Snowflake.TryParse(mention[3..^1], out id))
if (Snowflake.TryParse(mention[3..^1], out roleId))
return true;
}
else
id = default;
roleId = default;

return false;
}

public static ulong ParseRole(ReadOnlySpan<char> mention)
public static ulong ParseRole(ReadOnlySpan<char> roleMention)
{
if (TryParseRole(mention, out ulong id))
if (TryParseRole(roleMention, out ulong id))
return id;
else
throw new FormatException("Cannot parse the mention.");
}

public static string ApplicationCommand(string name, ulong commandId) => ApplicationCommandCore(name, commandId);

internal static string ApplicationCommandCore(string fullName, ulong commandId) => $"</{fullName}:{commandId}>";

public static string ApplicationCommand(string name, string subCommandName, ulong commandId) => $"</{name} {subCommandName}:{commandId}>";

public static string ApplicationCommand(string name, string subCommandGroupName, string subCommandName, ulong commandId) => $"</{name} {subCommandGroupName} {subCommandName}:{commandId}>";

public static bool TryFormatApplicationCommand(Span<char> destination, out int charsWritten, ulong commandId, ReadOnlySpan<char> name)
{
var pathLength = name.Length;
var idOffset = 3 + pathLength;
if (destination.Length < 5 + pathLength || !commandId.TryFormat(destination[idOffset..^1], out int length))
{
charsWritten = 0;
return false;
}

"</".CopyTo(destination);
name.CopyTo(destination[2..]);
destination[2 + pathLength] = ':';
destination[idOffset + length] = '>';
charsWritten = idOffset + length + 1;
return true;
}

public static bool TryFormatApplicationCommand(Span<char> destination, out int charsWritten, ulong commandId, ReadOnlySpan<char> name, ReadOnlySpan<char> subCommandName)
{
var nameLength = name.Length;
var subCommandNameLength = subCommandName.Length;
var pathLength = nameLength + subCommandNameLength + 1;
var idOffset = 3 + pathLength;
if (destination.Length < 5 + pathLength || !commandId.TryFormat(destination[idOffset..^1], out int length))
{
charsWritten = 0;
return false;
}

"</".CopyTo(destination);
name.CopyTo(destination[2..]);
destination[2 + nameLength] = ' ';
subCommandName.CopyTo(destination[(3 + nameLength)..]);
destination[3 + nameLength + subCommandNameLength] = ':';
destination[idOffset + length] = '>';
charsWritten = idOffset + length + 1;
return true;
}

public static bool TryFormatApplicationCommand(Span<char> destination, out int charsWritten, ulong commandId, ReadOnlySpan<char> name, ReadOnlySpan<char> subCommandGroupName, ReadOnlySpan<char> subCommandName)
{
var nameLength = name.Length;
var subCommandGroupNameLength = subCommandGroupName.Length;
var subCommandNameLength = subCommandName.Length;
var pathLength = nameLength + subCommandGroupNameLength + subCommandNameLength + 2;
var idOffset = 3 + pathLength;
if (destination.Length < 5 + pathLength || !commandId.TryFormat(destination[idOffset..^1], out int length))
{
charsWritten = 0;
return false;
}

"</".CopyTo(destination);
name.CopyTo(destination[2..]);
destination[2 + nameLength] = ' ';
subCommandGroupName.CopyTo(destination[(3 + nameLength)..]);
destination[3 + nameLength + subCommandGroupNameLength] = ' ';
subCommandName.CopyTo(destination[(4 + nameLength + subCommandGroupNameLength)..]);
destination[4 + nameLength + subCommandGroupNameLength + subCommandNameLength] = ':';
destination[idOffset + length] = '>';
charsWritten = idOffset + length + 1;
return true;
}

public static bool TryParseSlashCommand(ReadOnlySpan<char> mention, [MaybeNullWhen(false)] out SlashCommandMention result)
{
if (mention is ['<', '/', .., '>'])
Expand All @@ -94,6 +188,7 @@ public static bool TryParseSlashCommand(ReadOnlySpan<char> mention, [MaybeNullWh
s[i] = names[..x].ToString();
names = names[(x + 1)..];
}

i++;
}

Expand All @@ -118,9 +213,9 @@ public static bool TryParseSlashCommand(ReadOnlySpan<char> mention, [MaybeNullWh
return false;
}

public static SlashCommandMention ParseSlashCommand(ReadOnlySpan<char> mention)
public static SlashCommandMention ParseSlashCommand(ReadOnlySpan<char> slashCommandMention)
{
if (TryParseSlashCommand(mention, out var result))
if (TryParseSlashCommand(slashCommandMention, out var result))
return result;
else
throw new FormatException("Cannot parse the mention.");
Expand Down Expand Up @@ -152,21 +247,6 @@ public static GuildNavigation ParseGuildNavigation(ReadOnlySpan<char> mention)
throw new FormatException("Cannot parse the mention.");
}

public static bool TryFormatUser(Span<char> destination, out int charsWritten, ulong id)
{
return TryFormat(destination, out charsWritten, id, "<@", ">");
}

public static bool TryFormatChannel(Span<char> destination, out int charsWritten, ulong id)
{
return TryFormat(destination, out charsWritten, id, "<#", ">");
}

public static bool TryFormatRole(Span<char> destination, out int charsWritten, ulong id)
{
return TryFormat(destination, out charsWritten, id, "<@&", ">");
}

private static bool TryFormat(Span<char> destination, out int charsWritten, ulong id, ReadOnlySpan<char> prefix, ReadOnlySpan<char> suffix)
{
if (destination.Length <= prefix.Length + suffix.Length || !id.TryFormat(destination[prefix.Length..^suffix.Length], out int length))
Expand Down
23 changes: 4 additions & 19 deletions NetCord/Rest/ApplicationCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,23 +67,8 @@ public partial class ApplicationCommand(JsonModels.JsonApplicationCommand jsonMo
/// </summary>
public ulong Version => _jsonModel.Version;

public override string ToString() => $"</{Name}:{Id}>";

public override bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
{
var requiredLength = 5 + Name.Length;
if (destination.Length < requiredLength || !Id.TryFormat(destination[(3 + Name.Length)..^1], out int length))
{
charsWritten = 0;
return false;
}

"</".CopyTo(destination);
Name.CopyTo(destination[2..]);
destination[2 + Name.Length] = ':';
destination[3 + Name.Length + length] = '>';

charsWritten = 4 + Name.Length + length;
return true;
}
public override string ToString() => Mention.ApplicationCommand(Name, Id);

public override bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null) =>
Mention.TryFormatApplicationCommand(destination, out charsWritten, Id, Name);
}
21 changes: 3 additions & 18 deletions NetCord/Rest/ApplicationCommandOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,25 +94,10 @@ public ApplicationCommandOption(JsonModels.JsonApplicationCommandOption jsonMode
Options = options.Select(o => new ApplicationCommandOption(o, _fullName, _parentId)).ToArray();
}

public override string ToString() => $"</{_fullName}:{_parentId}>";
public override string ToString() => Mention.ApplicationCommandCore(_fullName, _parentId);

public string ToString(string? format, IFormatProvider? formatProvider) => ToString();

public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
{
var requiredLength = 5 + _fullName.Length;
if (destination.Length < requiredLength || !_parentId.TryFormat(destination[(3 + _fullName.Length)..^1], out int length))
{
charsWritten = 0;
return false;
}

"</".CopyTo(destination);
_fullName.CopyTo(destination[2..]);
destination[2 + _fullName.Length] = ':';
destination[3 + _fullName.Length + length] = '>';

charsWritten = 4 + _fullName.Length + length;
return true;
}
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null) =>
Mention.TryFormatApplicationCommand(destination, out charsWritten, _parentId, _fullName);
}
2 changes: 1 addition & 1 deletion NetCord/Role.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public Role(JsonRole jsonModel, ulong guildId, RestClient client) : base(client)
/// <returns>An <see cref="ImageUrl"/> pointing to the role's icon. If the role does not have one set, returns <see langword="null"/>.</returns>
public ImageUrl? GetIconUrl(ImageFormat format) => IconHash is string hash ? ImageUrl.RoleIcon(Id, hash, format) : null;

public override string ToString() => $"<@&{Id}>";
public override string ToString() => Mention.Role(Id);

public override bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null) => Mention.TryFormatRole(destination, out charsWritten, Id);
}
Expand Down
Loading