using System;
using System.Collections.Generic;
using System.Text;
namespace Spectre.Console
{
///
/// Utility for working with emojis.
///
public static partial class Emoji
{
private static readonly Dictionary _remappings;
static Emoji()
{
_remappings = new Dictionary(StringComparer.OrdinalIgnoreCase);
}
///
/// Remaps a specific emoji tag with a new emoji.
///
/// The emoji tag.
/// The emoji.
public static void Remap(string tag, string emoji)
{
if (tag is null)
{
throw new ArgumentNullException(nameof(tag));
}
if (emoji is null)
{
throw new ArgumentNullException(nameof(emoji));
}
tag = tag.TrimStart(':').TrimEnd(':');
emoji = emoji.TrimStart(':').TrimEnd(':');
_remappings[tag] = emoji;
}
#if NETSTANDARD2_0
///
/// Replaces emoji markup with corresponding unicode characters.
///
/// A string with emojis codes, e.g. "Hello :smiley:!".
/// A string with emoji codes replaced with actual emoji.
public static string Replace(string value)
{
return Replace(value.AsSpan());
}
#endif
///
/// Replaces emoji markup with corresponding unicode characters.
///
/// A string with emojis codes, e.g. "Hello :smiley:!".
/// A string with emoji codes replaced with actual emoji.
public static string Replace(ReadOnlySpan value)
{
var output = new StringBuilder();
var colonPos = value.IndexOf(':');
if (colonPos == -1)
{
// No colons, no emoji. return what was passed in with no changes.
return value.ToString();
}
while ((colonPos = value.IndexOf(':')) != -1)
{
// Append text up to colon
output.AppendSpan(value.Slice(0, colonPos));
// Set value equal to that colon and the rest of the string
value = value.Slice(colonPos);
// Find colon after that. if no colon, break out
var nextColonPos = value.IndexOf(':', 1);
if (nextColonPos == -1)
{
break;
}
// Get the emoji text minus the colons
var emojiKey = value.Slice(1, nextColonPos - 1).ToString();
if (TryGetEmoji(emojiKey, out var emojiValue))
{
output.Append(emojiValue);
value = value.Slice(nextColonPos + 1);
}
else
{
output.Append(':');
value = value.Slice(1);
}
}
output.AppendSpan(value);
return output.ToString();
}
private static bool TryGetEmoji(string emoji, out string value)
{
if (_remappings.TryGetValue(emoji, out var remappedEmojiValue))
{
value = remappedEmojiValue;
return true;
}
if (_emojis.TryGetValue(emoji, out var emojiValue))
{
value = emojiValue;
return true;
}
value = string.Empty;
return false;
}
private static int IndexOf(this ReadOnlySpan span, char value, int startIndex)
{
var indexInSlice = span.Slice(startIndex).IndexOf(value);
if (indexInSlice == -1)
{
return -1;
}
return startIndex + indexInSlice;
}
}
}