summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs136
-rw-r--r--src/SMAPI.Internal/ConsoleWriting/LogLevel.cs27
-rw-r--r--src/SMAPI.Internal/ConsoleWriting/MonitorColorScheme.cs (renamed from src/SMAPI/Framework/Models/MonitorColorScheme.cs)2
-rw-r--r--src/SMAPI.Internal/SMAPI.Internal.projitems3
-rw-r--r--src/SMAPI/Framework/Logging/ConsoleInterceptionManager.cs27
-rw-r--r--src/SMAPI/Framework/Models/SConfig.cs2
-rw-r--r--src/SMAPI/Framework/Monitor.cs111
-rw-r--r--src/SMAPI/LogLevel.cs16
-rw-r--r--src/SMAPI/StardewModdingAPI.csproj1
9 files changed, 196 insertions, 129 deletions
diff --git a/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs b/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs
new file mode 100644
index 00000000..5f8fe271
--- /dev/null
+++ b/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Collections.Generic;
+
+namespace StardewModdingAPI.Internal.ConsoleWriting
+{
+ /// <summary>Provides a wrapper for writing color-coded text to the console.</summary>
+ internal class ColorfulConsoleWriter
+ {
+ /*********
+ ** Properties
+ *********/
+ /// <summary>The console text color for each log level.</summary>
+ private readonly IDictionary<ConsoleLogLevel, ConsoleColor> Colors;
+
+ /// <summary>Whether the current console supports color formatting.</summary>
+ private readonly bool SupportsColor;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="platform">The target platform.</param>
+ /// <param name="colorScheme">The console color scheme to use.</param>
+ public ColorfulConsoleWriter(Platform platform, MonitorColorScheme colorScheme)
+ {
+ this.SupportsColor = this.TestColorSupport();
+ this.Colors = this.GetConsoleColorScheme(platform, colorScheme);
+ }
+
+ /// <summary>Write a message line to the log.</summary>
+ /// <param name="message">The message to log.</param>
+ /// <param name="level">The log level.</param>
+ public void WriteLine(string message, ConsoleLogLevel level)
+ {
+ if (this.SupportsColor)
+ {
+ if (level == ConsoleLogLevel.Critical)
+ {
+ Console.BackgroundColor = ConsoleColor.Red;
+ Console.ForegroundColor = ConsoleColor.White;
+ Console.WriteLine(message);
+ Console.ResetColor();
+ }
+ else
+ {
+ Console.ForegroundColor = this.Colors[level];
+ Console.WriteLine(message);
+ Console.ResetColor();
+ }
+ }
+ else
+ Console.WriteLine(message);
+ }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// <summary>Test whether the current console supports color formatting.</summary>
+ private bool TestColorSupport()
+ {
+ try
+ {
+ Console.ForegroundColor = Console.ForegroundColor;
+ return true;
+ }
+ catch (Exception)
+ {
+ return false; // Mono bug
+ }
+ }
+
+ /// <summary>Get the color scheme to use for the current console.</summary>
+ /// <param name="platform">The target platform.</param>
+ /// <param name="colorScheme">The console color scheme to use.</param>
+ private IDictionary<ConsoleLogLevel, ConsoleColor> GetConsoleColorScheme(Platform platform, MonitorColorScheme colorScheme)
+ {
+ // auto detect color scheme
+ if (colorScheme == MonitorColorScheme.AutoDetect)
+ {
+ colorScheme = platform == Platform.Mac
+ ? MonitorColorScheme.LightBackground // MacOS doesn't provide console background color info, but it's usually white.
+ : ColorfulConsoleWriter.IsDark(Console.BackgroundColor) ? MonitorColorScheme.DarkBackground : MonitorColorScheme.LightBackground;
+ }
+
+ // get colors for scheme
+ switch (colorScheme)
+ {
+ case MonitorColorScheme.DarkBackground:
+ return new Dictionary<ConsoleLogLevel, ConsoleColor>
+ {
+ [ConsoleLogLevel.Trace] = ConsoleColor.DarkGray,
+ [ConsoleLogLevel.Debug] = ConsoleColor.DarkGray,
+ [ConsoleLogLevel.Info] = ConsoleColor.White,
+ [ConsoleLogLevel.Warn] = ConsoleColor.Yellow,
+ [ConsoleLogLevel.Error] = ConsoleColor.Red,
+ [ConsoleLogLevel.Alert] = ConsoleColor.Magenta
+ };
+
+ case MonitorColorScheme.LightBackground:
+ return new Dictionary<ConsoleLogLevel, ConsoleColor>
+ {
+ [ConsoleLogLevel.Trace] = ConsoleColor.DarkGray,
+ [ConsoleLogLevel.Debug] = ConsoleColor.DarkGray,
+ [ConsoleLogLevel.Info] = ConsoleColor.Black,
+ [ConsoleLogLevel.Warn] = ConsoleColor.DarkYellow,
+ [ConsoleLogLevel.Error] = ConsoleColor.Red,
+ [ConsoleLogLevel.Alert] = ConsoleColor.DarkMagenta
+ };
+
+ default:
+ throw new NotSupportedException($"Unknown color scheme '{colorScheme}'.");
+ }
+ }
+
+ /// <summary>Get whether a console color should be considered dark, which is subjectively defined as 'white looks better than black on this text'.</summary>
+ /// <param name="color">The color to check.</param>
+ 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.Internal/ConsoleWriting/LogLevel.cs b/src/SMAPI.Internal/ConsoleWriting/LogLevel.cs
new file mode 100644
index 00000000..85e69f51
--- /dev/null
+++ b/src/SMAPI.Internal/ConsoleWriting/LogLevel.cs
@@ -0,0 +1,27 @@
+namespace StardewModdingAPI.Internal.ConsoleWriting
+{
+ /// <summary>The log severity levels.</summary>
+ internal enum ConsoleLogLevel
+ {
+ /// <summary>Tracing info intended for developers.</summary>
+ Trace,
+
+ /// <summary>Troubleshooting info that may be relevant to the player.</summary>
+ Debug,
+
+ /// <summary>Info relevant to the player. This should be used judiciously.</summary>
+ Info,
+
+ /// <summary>An issue the player should be aware of. This should be used rarely.</summary>
+ Warn,
+
+ /// <summary>A message indicating something went wrong.</summary>
+ Error,
+
+ /// <summary>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.</summary>
+ Alert,
+
+ /// <summary>A critical issue that generally signals an immediate end to the application.</summary>
+ Critical
+ }
+}
diff --git a/src/SMAPI/Framework/Models/MonitorColorScheme.cs b/src/SMAPI.Internal/ConsoleWriting/MonitorColorScheme.cs
index d8289d08..bccb56d7 100644
--- a/src/SMAPI/Framework/Models/MonitorColorScheme.cs
+++ b/src/SMAPI.Internal/ConsoleWriting/MonitorColorScheme.cs
@@ -1,4 +1,4 @@
-namespace StardewModdingAPI.Framework.Models
+namespace StardewModdingAPI.Internal.ConsoleWriting
{
/// <summary>A monitor color scheme to use.</summary>
internal enum MonitorColorScheme
diff --git a/src/SMAPI.Internal/SMAPI.Internal.projitems b/src/SMAPI.Internal/SMAPI.Internal.projitems
index 764cb12e..dadae4b0 100644
--- a/src/SMAPI.Internal/SMAPI.Internal.projitems
+++ b/src/SMAPI.Internal/SMAPI.Internal.projitems
@@ -9,9 +9,12 @@
<Import_RootNamespace>SMAPI.Internal</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
+ <Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\ColorfulConsoleWriter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)EnvironmentUtility.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\LogLevel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Models\ModInfoModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Models\ModSeachModel.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\MonitorColorScheme.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Platform.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SemanticVersionImpl.cs" />
</ItemGroup>
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
*********/
- /// <summary>Whether the current console supports color formatting.</summary>
- public bool SupportsColor { get; }
-
/// <summary>The event raised when a message is written to the console directly.</summary>
public event Action<string> 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();
}
/// <summary>Get an exclusive lock and write to the console output without interception.</summary>
@@ -61,26 +55,5 @@ namespace StardewModdingAPI.Framework.Logging
Console.SetOut(this.Output.Out);
this.Output.Dispose();
}
-
-
- /*********
- ** private methods
- *********/
- /// <summary>Test whether the current console supports color formatting.</summary>
- 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/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
{
/// <summary>The SMAPI configuration settings.</summary>
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
/// <summary>The name of the module which logs messages using this instance.</summary>
private readonly string Source;
+ /// <summary>Handles writing color-coded text to the console.</summary>
+ private readonly ColorfulConsoleWriter ConsoleWriter;
+
/// <summary>Manages access to the console output.</summary>
- private readonly ConsoleInterceptionManager ConsoleManager;
+ private readonly ConsoleInterceptionManager ConsoleInterceptor;
/// <summary>The log file to which to write messages.</summary>
private readonly LogFileManager LogFile;
@@ -26,9 +27,6 @@ namespace StardewModdingAPI.Framework
/// <summary>The maximum length of the <see cref="LogLevel"/> values.</summary>
private static readonly int MaxLevelLength = (from level in Enum.GetValues(typeof(LogLevel)).Cast<LogLevel>() select level.ToString().Length).Max();
- /// <summary>The console text color for each log level.</summary>
- private readonly IDictionary<LogLevel, ConsoleColor> Colors;
-
/// <summary>Propagates notification that SMAPI should exit.</summary>
private readonly CancellationTokenSource ExitTokenSource;
@@ -54,21 +52,21 @@ namespace StardewModdingAPI.Framework
*********/
/// <summary>Construct an instance.</summary>
/// <param name="source">The name of the module which logs messages using this instance.</param>
- /// <param name="consoleManager">Manages access to the console output.</param>
+ /// <param name="consoleInterceptor">Intercepts access to the console output.</param>
/// <param name="logFile">The log file to which to write messages.</param>
/// <param name="exitTokenSource">Propagates notification that SMAPI should exit.</param>
/// <param name="colorScheme">The console color scheme to use.</param>
- 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
/// <param name="level">The log severity level.</param>
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);
}
/// <summary>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.</summary>
@@ -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
/// <param name="message">The message to log.</param>
private void LogFatal(string message)
{
- this.LogImpl(this.Source, message, LogLevel.Error, ConsoleColor.White, background: ConsoleColor.Red);
+ this.LogImpl(this.Source, message, ConsoleLogLevel.Critical);
}
/// <summary>Write a message line to the log.</summary>
/// <param name="source">The name of the mod logging the message.</param>
/// <param name="message">The message to log.</param>
/// <param name="level">The log level.</param>
- /// <param name="color">The console foreground color.</param>
- /// <param name="background">The console background color (or <c>null</c> to leave it as-is).</param>
- 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
/// <summary>Generate a message prefix for the current time.</summary>
/// <param name="source">The name of the mod logging the message.</param>
/// <param name="level">The log level.</param>
- 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}]";
}
-
- /// <summary>Get the color scheme to use for the current console.</summary>
- /// <param name="colorScheme">The console color scheme to use.</param>
- private static IDictionary<LogLevel, ConsoleColor> 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, ConsoleColor>
- {
- [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, ConsoleColor>
- {
- [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}'.");
- }
- }
-
- /// <summary>Get whether a console color should be considered dark, which is subjectively defined as 'white looks better than black on this text'.</summary>
- /// <param name="color">The color to check.</param>
- 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
{
/// <summary>The log severity levels.</summary>
public enum LogLevel
{
/// <summary>Tracing info intended for developers.</summary>
- Trace,
+ Trace = ConsoleLogLevel.Trace,
/// <summary>Troubleshooting info that may be relevant to the player.</summary>
- Debug,
+ Debug = ConsoleLogLevel.Debug,
/// <summary>Info relevant to the player. This should be used judiciously.</summary>
- Info,
+ Info = ConsoleLogLevel.Info,
/// <summary>An issue the player should be aware of. This should be used rarely.</summary>
- Warn,
+ Warn = ConsoleLogLevel.Warn,
/// <summary>A message indicating something went wrong.</summary>
- Error,
+ Error = ConsoleLogLevel.Error,
/// <summary>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.</summary>
- 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 @@
<Compile Include="Framework\SContentManager.cs" />
<Compile Include="Framework\Exceptions\SAssemblyLoadFailedException.cs" />
<Compile Include="Framework\ModLoading\AssemblyLoadStatus.cs" />
- <Compile Include="Framework\Models\MonitorColorScheme.cs" />
<Compile Include="Framework\Reflection\InterfaceProxyBuilder.cs" />
<Compile Include="Framework\Reflection\InterfaceProxyFactory.cs" />
<Compile Include="Framework\RewriteFacades\SpriteBatchMethods.cs" />