From c453717998f44a2c8fbb1635a41aca079ec69f41 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Mon, 17 Feb 2020 21:38:58 -0500 Subject: [PATCH] feat: First attempt at an ANSI to HTML converter --- CHANGELOG.md | 1 + .../Converters/AnsiToHtmlTest.cs | 22 ++++++ ICD.Common.Utils/Converters/AnsiToHtml.cs | 74 +++++++++++++++++++ .../ICD.Common.Utils_SimplSharp.csproj | 1 + 4 files changed, 98 insertions(+) create mode 100644 ICD.Common.Utils.Tests/Converters/AnsiToHtmlTest.cs create mode 100644 ICD.Common.Utils/Converters/AnsiToHtml.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 2062021..6ef055f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Added public access to GetValues enumeration extension - Added extensions for getting JsonReader values as long or ulong - Added DateTimeUtils methods for creating DateTimes from epoch seconds or milliseconds + - Added AnsiToHtml converter for visualizing ANSI logs ### Changed - Fixed exception trying to get DHCP status of network interfaces on Linux diff --git a/ICD.Common.Utils.Tests/Converters/AnsiToHtmlTest.cs b/ICD.Common.Utils.Tests/Converters/AnsiToHtmlTest.cs new file mode 100644 index 0000000..4d14e5a --- /dev/null +++ b/ICD.Common.Utils.Tests/Converters/AnsiToHtmlTest.cs @@ -0,0 +1,22 @@ +using ICD.Common.Utils.Converters; +using NUnit.Framework; + +namespace ICD.Common.Utils.Tests.Converters +{ + [TestFixture] + public sealed class AnsiToHtmlTest + { + [TestCase("black\x1b[37mwhite", + @"blackwhite")] + [TestCase("black\x1b[0mblack", + @"blackblack")] + [TestCase("black\x1b[37mwhite\x1b[0m", + @"blackwhite")] + [TestCase("\x1b[30mblack\x1b[37mwhite", + @"blackwhite")] + public void ConvertTest(string ansi, string expected) + { + Assert.AreEqual(expected, AnsiToHtml.Convert(ansi)); + } + } +} diff --git a/ICD.Common.Utils/Converters/AnsiToHtml.cs b/ICD.Common.Utils/Converters/AnsiToHtml.cs new file mode 100644 index 0000000..6dac84d --- /dev/null +++ b/ICD.Common.Utils/Converters/AnsiToHtml.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; + +namespace ICD.Common.Utils.Converters +{ + public static class AnsiToHtml + { + /// + /// Matches ANSI escape codes, e.g. \x1b[31m and \x1b[30;1m + /// + private const string ANSI_PATTERN = "(?'match'\x01b\\[(?'code'[\\d;]+)m)"; + + private const string CODE_RESET = "0"; + + /// + /// Matches ANSI escape codes to HTML styles. + /// Color values are taken from PuTTY. + /// + private static readonly Dictionary s_Colors = + new Dictionary + { + {"30", "color:#000000"}, // Black + {"31", "color:#BB0000"}, // Red + {"32", "color:#00BB00"}, // Green + {"33", "color:#BBBB00"}, // Yellow + {"34", "color:#0000BB"}, // Blue + {"35", "color:#BB00BB"}, // Magenta + {"36", "color:#00BBBB"}, // Cyan + {"37", "color:#BBBBBB"}, // White + + {"30;1", "color:#555555"}, // Bright Black + {"31;1", "color:#FF5555"}, // Bright Red + {"32;1", "color:#55FF55"}, // Bright Green + {"33;1", "color:#FFFF55"}, // Bright Yellow + {"34;1", "color:#5555FF"}, // Bright Blue + {"35;1", "color:#FF55FF"}, // Bright Magenta + {"36;1", "color:#55FFFF"}, // Bright Cyan + {"37;1", "color:#FFFFFF"}, // Bright White + }; + + /// + /// Converts the input ansi string into html with color attributes. + /// + /// + /// + public static string Convert(string ansi) + { + int depth = 0; + + // Hack - Append a reset to close any open spans + ansi += "\x1b[0m"; + + return RegexUtils.ReplaceGroup(ansi, ANSI_PATTERN, "match", match => + { + string code = match.Groups["code"].Value; + + // Reset code - close all of the open spans. + if (code == CODE_RESET) + { + string output = StringUtils.Repeat("", depth); + depth = 0; + return output; + } + + string style; + if (!s_Colors.TryGetValue(code, out style)) + return match.Value; + + depth++; + return string.Format("", style); + }); + } + } +} \ No newline at end of file diff --git a/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj b/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj index 432936a..bc0cfbb 100644 --- a/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj +++ b/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj @@ -86,6 +86,7 @@ +