diff --git a/Robust.Shared/Utility/FormattedMessage.cs b/Robust.Shared/Utility/FormattedMessage.cs
index 364e526d974..b19ab5d2974 100644
--- a/Robust.Shared/Utility/FormattedMessage.cs
+++ b/Robust.Shared/Utility/FormattedMessage.cs
@@ -235,6 +235,40 @@ public void Clear()
_nodes.Clear();
}
+ ///
+ /// Removes excess whitespace at the end of markup.
+ ///
+ public void TrimEnd()
+ {
+ for (var i = _nodes.Count - 1; i >= 0; i--)
+ {
+ var node = _nodes[i];
+ var markup = node.Value;
+
+ if (markup.StringValue == null)
+ break;
+
+ var value = markup.StringValue.Trim();
+
+ // If we stripped all text then remove the node and continue.
+ if (string.IsNullOrEmpty(value))
+ {
+ _nodes.RemoveAt(i);
+ continue;
+ }
+
+ // Only trimmed some of it so update node and stop.
+ if (value != node.Value.StringValue)
+ {
+ _nodes.RemoveAt(i);
+ markup = markup with { StringValue = value };
+ _nodes.Add(new MarkupNode(value, markup, node.Attributes));
+ }
+
+ break;
+ }
+ }
+
///
/// Returns an enumerator that enumerates every rune for each text node contained in this formatted text instance.
///
diff --git a/Robust.UnitTesting/Shared/Utility/FormattedMessage_Test.cs b/Robust.UnitTesting/Shared/Utility/FormattedMessage_Test.cs
index 0af1da290cc..788d3a8aa84 100644
--- a/Robust.UnitTesting/Shared/Utility/FormattedMessage_Test.cs
+++ b/Robust.UnitTesting/Shared/Utility/FormattedMessage_Test.cs
@@ -10,6 +10,30 @@ namespace Robust.UnitTesting.Shared.Utility
[TestOf(typeof(FormattedMessage))]
public sealed class FormattedMessage_Test
{
+ private static (FormattedMessage Message, bool Trimmed)[] _trimMessages = new[]
+ {
+ (FormattedMessage.FromUnformatted("weh"), false),
+ (FormattedMessage.FromUnformatted("weh "), true),
+ (FormattedMessage.Empty, false),
+ (FormattedMessage.FromUnformatted("weh\n"), true),
+ };
+
+ [Test, TestCaseSource(nameof(_trimMessages))]
+ public static void TestTrimEnd((FormattedMessage message, bool shouldTrim) test)
+ {
+ var copy = FormattedMessage.FromUnformatted(test.message.ToString());
+ copy.TrimEnd();
+
+ if (test.shouldTrim)
+ {
+ Assert.That(copy.ToString(), Is.Not.EqualTo(test.message.ToString()));
+ }
+ else
+ {
+ Assert.That(copy.ToString(), Is.EqualTo(test.message.ToString()));
+ }
+ }
+
[Test]
public static void TestParseMarkup()
{