From a8985e122e9ebd3cb1545971474b95d34058f896 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 15 Jan 2022 12:21:22 -0500 Subject: [PATCH] fix suppressed console output not suppressing newlines --- docs/release-notes.md | 1 + .../Logging/InterceptingTextWriter.cs | 12 ++++++++++- src/SMAPI/Framework/Logging/LogManager.cs | 20 +++++++++++++++---- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/docs/release-notes.md b/docs/release-notes.md index 1df0af0e..735c7c12 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -5,6 +5,7 @@ * For players: * SMAPI now auto-fixes maps loaded without a required tilesheet to prevent errors. * Added the new game build number to the SMAPI console + log. + * Fixed extra newlines shown in the console in non-developer mode. * Fixed outdated instructions in Steam error message. * Fixed uninstaller not removing `StardewModdingAPI.deps.json` file. * Fixed launch issue on macOS when using some terminals (thanks to bruce2409!). diff --git a/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs b/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs index d99f1dd2..41a3abcb 100644 --- a/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs +++ b/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs @@ -26,6 +26,10 @@ namespace StardewModdingAPI.Framework.Logging /// The event raised when a message is written to the console directly. public event Action OnMessageIntercepted; + /// Whether the text writer should ignore the next input if it's a newline. + /// This is used when log output is suppressed from the console, since Console.WriteLine writes the trailing newline as a separate call. + public bool IgnoreNextIfNewline { get; set; } + /********* ** Public methods @@ -42,12 +46,18 @@ namespace StardewModdingAPI.Framework.Logging /// public override void Write(char[] buffer, int index, int count) { + bool ignoreIfNewline = this.IgnoreNextIfNewline; + this.IgnoreNextIfNewline = false; + if (buffer.Length == 0) this.Out.Write(buffer, index, count); else if (buffer[0] == this.IgnoreChar) this.Out.Write(buffer, index + 1, count - 1); else if (this.IsEmptyOrNewline(buffer)) - this.Out.Write(buffer, index, count); + { + if (!ignoreIfNewline) + this.Out.Write(buffer, index, count); + } else this.OnMessageIntercepted?.Invoke(new string(buffer, index, count).TrimEnd('\r', '\n')); } diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs index 90433c37..acd2c617 100644 --- a/src/SMAPI/Framework/Logging/LogManager.cs +++ b/src/SMAPI/Framework/Logging/LogManager.cs @@ -22,9 +22,15 @@ namespace StardewModdingAPI.Framework.Logging /********* ** Fields *********/ + /// Whether to show trace messages in the console. + private readonly bool ShowTraceInConsole; + /// The log file to which to write messages. private readonly LogFileManager LogFile; + /// The text writer which intercepts console output. + private readonly InterceptingTextWriter ConsoleInterceptor; + /// Prefixing a low-level message with this character indicates that the console interceptor should write the string without intercepting it. (The character itself is not written.) private readonly char IgnoreChar = '\u200B'; @@ -91,10 +97,11 @@ namespace StardewModdingAPI.Framework.Logging public LogManager(string logPath, ColorSchemeConfig colorConfig, bool writeToConsole, bool isVerbose, bool isDeveloperMode, Func getScreenIdForLog) { // init construction logic + this.ShowTraceInConsole = isDeveloperMode; this.GetMonitorImpl = name => new Monitor(name, this.IgnoreChar, this.LogFile, colorConfig, isVerbose, getScreenIdForLog) { WriteToConsole = writeToConsole, - ShowTraceInConsole = isDeveloperMode, + ShowTraceInConsole = this.ShowTraceInConsole, ShowFullStampInConsole = isDeveloperMode }; @@ -104,10 +111,10 @@ namespace StardewModdingAPI.Framework.Logging this.MonitorForGame = this.GetMonitor("game"); // redirect direct console output - var output = new InterceptingTextWriter(Console.Out, this.IgnoreChar); + this.ConsoleInterceptor = new InterceptingTextWriter(Console.Out, this.IgnoreChar); if (writeToConsole) - output.OnMessageIntercepted += message => this.HandleConsoleMessage(this.MonitorForGame, message); - Console.SetOut(output); + this.ConsoleInterceptor.OnMessageIntercepted += message => this.HandleConsoleMessage(this.MonitorForGame, message); + Console.SetOut(this.ConsoleInterceptor); // enable Unicode handling on Windows // (the terminal defaults to UTF-8 on Linux/macOS) @@ -363,7 +370,10 @@ namespace StardewModdingAPI.Framework.Logging // ignore suppressed message if (level != LogLevel.Error && this.SuppressConsolePatterns.Any(p => p.IsMatch(message))) + { + this.ConsoleInterceptor.IgnoreNextIfNewline = true; return; + } // show friendly error if applicable foreach (ReplaceLogPattern entry in this.ReplaceConsolePatterns) @@ -383,6 +393,8 @@ namespace StardewModdingAPI.Framework.Logging // forward to monitor gameMonitor.Log(message, level); + if (level == LogLevel.Trace && !this.ShowTraceInConsole) + this.ConsoleInterceptor.IgnoreNextIfNewline = true; } /// Write a summary of mod warnings to the console and log.