From 02c02a55eeeb744108d6a8335f6203a95ea20626 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 10 May 2018 00:47:20 -0400 Subject: generalise console color logic for reuse (#495) --- .../Logging/ConsoleInterceptionManager.cs | 27 ----- src/SMAPI/Framework/Models/MonitorColorScheme.cs | 15 --- src/SMAPI/Framework/Models/SConfig.cs | 2 + src/SMAPI/Framework/Monitor.cs | 111 ++++----------------- src/SMAPI/LogLevel.cs | 16 +-- src/SMAPI/StardewModdingAPI.csproj | 1 - 6 files changed, 29 insertions(+), 143 deletions(-) delete mode 100644 src/SMAPI/Framework/Models/MonitorColorScheme.cs (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/Logging/ConsoleInterceptionManager.cs b/src/SMAPI/Framework/Logging/ConsoleInterceptionManager.cs index b8f2c34e..c04bcd1a 100644 --- a/src/SMAPI/Framework/Logging/ConsoleInterceptionManager.cs +++ b/src/SMAPI/Framework/Logging/ConsoleInterceptionManager.cs @@ -15,9 +15,6 @@ namespace StardewModdingAPI.Framework.Logging /********* ** Accessors *********/ - /// Whether the current console supports color formatting. - public bool SupportsColor { get; } - /// The event raised when a message is written to the console directly. public event Action OnMessageIntercepted; @@ -32,9 +29,6 @@ namespace StardewModdingAPI.Framework.Logging this.Output = new InterceptingTextWriter(Console.Out); this.Output.OnMessageIntercepted += line => this.OnMessageIntercepted?.Invoke(line); Console.SetOut(this.Output); - - // test color support - this.SupportsColor = this.TestColorSupport(); } /// Get an exclusive lock and write to the console output without interception. @@ -61,26 +55,5 @@ namespace StardewModdingAPI.Framework.Logging Console.SetOut(this.Output.Out); this.Output.Dispose(); } - - - /********* - ** private methods - *********/ - /// Test whether the current console supports color formatting. - private bool TestColorSupport() - { - try - { - this.ExclusiveWriteWithoutInterception(() => - { - Console.ForegroundColor = Console.ForegroundColor; - }); - return true; - } - catch (Exception) - { - return false; // Mono bug - } - } } } diff --git a/src/SMAPI/Framework/Models/MonitorColorScheme.cs b/src/SMAPI/Framework/Models/MonitorColorScheme.cs deleted file mode 100644 index d8289d08..00000000 --- a/src/SMAPI/Framework/Models/MonitorColorScheme.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace StardewModdingAPI.Framework.Models -{ - /// A monitor color scheme to use. - internal enum MonitorColorScheme - { - /// Choose a color scheme automatically. - AutoDetect, - - /// Use lighter text colors that look better on a black or dark background. - DarkBackground, - - /// Use darker text colors that look better on a white or light background. - LightBackground - } -} diff --git a/src/SMAPI/Framework/Models/SConfig.cs b/src/SMAPI/Framework/Models/SConfig.cs index b732921f..e201e966 100644 --- a/src/SMAPI/Framework/Models/SConfig.cs +++ b/src/SMAPI/Framework/Models/SConfig.cs @@ -1,3 +1,5 @@ +using StardewModdingAPI.Internal.ConsoleWriting; + namespace StardewModdingAPI.Framework.Models { /// The SMAPI configuration settings. diff --git a/src/SMAPI/Framework/Monitor.cs b/src/SMAPI/Framework/Monitor.cs index 8df2e59b..2812a9cc 100644 --- a/src/SMAPI/Framework/Monitor.cs +++ b/src/SMAPI/Framework/Monitor.cs @@ -1,10 +1,8 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Threading; using StardewModdingAPI.Framework.Logging; -using StardewModdingAPI.Framework.Models; -using StardewModdingAPI.Internal; +using StardewModdingAPI.Internal.ConsoleWriting; namespace StardewModdingAPI.Framework { @@ -17,8 +15,11 @@ namespace StardewModdingAPI.Framework /// The name of the module which logs messages using this instance. private readonly string Source; + /// Handles writing color-coded text to the console. + private readonly ColorfulConsoleWriter ConsoleWriter; + /// Manages access to the console output. - private readonly ConsoleInterceptionManager ConsoleManager; + private readonly ConsoleInterceptionManager ConsoleInterceptor; /// The log file to which to write messages. private readonly LogFileManager LogFile; @@ -26,9 +27,6 @@ namespace StardewModdingAPI.Framework /// The maximum length of the values. private static readonly int MaxLevelLength = (from level in Enum.GetValues(typeof(LogLevel)).Cast() select level.ToString().Length).Max(); - /// The console text color for each log level. - private readonly IDictionary Colors; - /// Propagates notification that SMAPI should exit. private readonly CancellationTokenSource ExitTokenSource; @@ -54,21 +52,21 @@ namespace StardewModdingAPI.Framework *********/ /// Construct an instance. /// The name of the module which logs messages using this instance. - /// Manages access to the console output. + /// Intercepts access to the console output. /// The log file to which to write messages. /// Propagates notification that SMAPI should exit. /// The console color scheme to use. - public Monitor(string source, ConsoleInterceptionManager consoleManager, LogFileManager logFile, CancellationTokenSource exitTokenSource, MonitorColorScheme colorScheme) + public Monitor(string source, ConsoleInterceptionManager consoleInterceptor, LogFileManager logFile, CancellationTokenSource exitTokenSource, MonitorColorScheme colorScheme) { // validate if (string.IsNullOrWhiteSpace(source)) throw new ArgumentException("The log source cannot be empty."); // initialise - this.Colors = Monitor.GetConsoleColorScheme(colorScheme); this.Source = source; this.LogFile = logFile ?? throw new ArgumentNullException(nameof(logFile), "The log file manager cannot be null."); - this.ConsoleManager = consoleManager; + this.ConsoleWriter = new ColorfulConsoleWriter(Constants.Platform, colorScheme); + this.ConsoleInterceptor = consoleInterceptor; this.ExitTokenSource = exitTokenSource; } @@ -77,7 +75,7 @@ namespace StardewModdingAPI.Framework /// The log severity level. public void Log(string message, LogLevel level = LogLevel.Debug) { - this.LogImpl(this.Source, message, level, this.Colors[level]); + this.LogImpl(this.Source, message, (ConsoleLogLevel)level); } /// Immediately exit the game without saving. This should only be invoked when an irrecoverable fatal error happens that risks save corruption or game-breaking bugs. @@ -92,7 +90,7 @@ namespace StardewModdingAPI.Framework internal void Newline() { if (this.WriteToConsole) - this.ConsoleManager.ExclusiveWriteWithoutInterception(Console.WriteLine); + this.ConsoleInterceptor.ExclusiveWriteWithoutInterception(Console.WriteLine); this.LogFile.WriteLine(""); } @@ -101,7 +99,7 @@ namespace StardewModdingAPI.Framework internal void LogUserInput(string input) { // user input already appears in the console, so just need to write to file - string prefix = this.GenerateMessagePrefix(this.Source, LogLevel.Info); + string prefix = this.GenerateMessagePrefix(this.Source, (ConsoleLogLevel)LogLevel.Info); this.LogFile.WriteLine($"{prefix} $>{input}"); } @@ -113,16 +111,14 @@ namespace StardewModdingAPI.Framework /// The message to log. private void LogFatal(string message) { - this.LogImpl(this.Source, message, LogLevel.Error, ConsoleColor.White, background: ConsoleColor.Red); + this.LogImpl(this.Source, message, ConsoleLogLevel.Critical); } /// Write a message line to the log. /// The name of the mod logging the message. /// The message to log. /// The log level. - /// The console foreground color. - /// The console background color (or null to leave it as-is). - private void LogImpl(string source, string message, LogLevel level, ConsoleColor color, ConsoleColor? background = null) + private void LogImpl(string source, string message, ConsoleLogLevel level) { // generate message string prefix = this.GenerateMessagePrefix(source, level); @@ -130,20 +126,11 @@ namespace StardewModdingAPI.Framework string consoleMessage = this.ShowFullStampInConsole ? fullMessage : $"[{source}] {message}"; // write to console - if (this.WriteToConsole && (this.ShowTraceInConsole || level != LogLevel.Trace)) + if (this.WriteToConsole && (this.ShowTraceInConsole || level != ConsoleLogLevel.Trace)) { - this.ConsoleManager.ExclusiveWriteWithoutInterception(() => + this.ConsoleInterceptor.ExclusiveWriteWithoutInterception(() => { - if (this.ConsoleManager.SupportsColor) - { - if (background.HasValue) - Console.BackgroundColor = background.Value; - Console.ForegroundColor = color; - Console.WriteLine(consoleMessage); - Console.ResetColor(); - } - else - Console.WriteLine(consoleMessage); + this.ConsoleWriter.WriteLine(consoleMessage, level); }); } @@ -154,72 +141,10 @@ namespace StardewModdingAPI.Framework /// Generate a message prefix for the current time. /// The name of the mod logging the message. /// The log level. - private string GenerateMessagePrefix(string source, LogLevel level) + private string GenerateMessagePrefix(string source, ConsoleLogLevel level) { string levelStr = level.ToString().ToUpper().PadRight(Monitor.MaxLevelLength); return $"[{DateTime.Now:HH:mm:ss} {levelStr} {source}]"; } - - /// Get the color scheme to use for the current console. - /// The console color scheme to use. - private static IDictionary GetConsoleColorScheme(MonitorColorScheme colorScheme) - { - // auto detect color scheme - if (colorScheme == MonitorColorScheme.AutoDetect) - { - if (Constants.Platform == Platform.Mac) - colorScheme = MonitorColorScheme.LightBackground; // MacOS doesn't provide console background color info, but it's usually white. - else - colorScheme = Monitor.IsDark(Console.BackgroundColor) ? MonitorColorScheme.DarkBackground : MonitorColorScheme.LightBackground; - } - - // get colors for scheme - switch (colorScheme) - { - case MonitorColorScheme.DarkBackground: - return new Dictionary - { - [LogLevel.Trace] = ConsoleColor.DarkGray, - [LogLevel.Debug] = ConsoleColor.DarkGray, - [LogLevel.Info] = ConsoleColor.White, - [LogLevel.Warn] = ConsoleColor.Yellow, - [LogLevel.Error] = ConsoleColor.Red, - [LogLevel.Alert] = ConsoleColor.Magenta - }; - - case MonitorColorScheme.LightBackground: - return new Dictionary - { - [LogLevel.Trace] = ConsoleColor.DarkGray, - [LogLevel.Debug] = ConsoleColor.DarkGray, - [LogLevel.Info] = ConsoleColor.Black, - [LogLevel.Warn] = ConsoleColor.DarkYellow, - [LogLevel.Error] = ConsoleColor.Red, - [LogLevel.Alert] = ConsoleColor.DarkMagenta - }; - - default: - throw new NotSupportedException($"Unknown color scheme '{colorScheme}'."); - } - } - - /// Get whether a console color should be considered dark, which is subjectively defined as 'white looks better than black on this text'. - /// The color to check. - private static bool IsDark(ConsoleColor color) - { - switch (color) - { - case ConsoleColor.Black: - case ConsoleColor.Blue: - case ConsoleColor.DarkBlue: - case ConsoleColor.DarkMagenta: // Powershell - case ConsoleColor.DarkRed: - case ConsoleColor.Red: - return true; - - default: - return false; - } - } } } diff --git a/src/SMAPI/LogLevel.cs b/src/SMAPI/LogLevel.cs index 89647876..7987f82a 100644 --- a/src/SMAPI/LogLevel.cs +++ b/src/SMAPI/LogLevel.cs @@ -1,24 +1,26 @@ +using StardewModdingAPI.Internal.ConsoleWriting; + namespace StardewModdingAPI { /// The log severity levels. public enum LogLevel { /// Tracing info intended for developers. - Trace, + Trace = ConsoleLogLevel.Trace, /// Troubleshooting info that may be relevant to the player. - Debug, + Debug = ConsoleLogLevel.Debug, /// Info relevant to the player. This should be used judiciously. - Info, + Info = ConsoleLogLevel.Info, /// An issue the player should be aware of. This should be used rarely. - Warn, + Warn = ConsoleLogLevel.Warn, /// A message indicating something went wrong. - Error, + Error = ConsoleLogLevel.Error, /// Important information to highlight for the player when player action is needed (e.g. new version available). This should be used rarely to avoid alert fatigue. - Alert + Alert = ConsoleLogLevel.Alert } -} \ No newline at end of file +} diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 320b97e7..01d5aaf1 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -125,7 +125,6 @@ - -- cgit