diff --git a/ConsoleInteractive/ConsoleInteractive/ConsoleBuffer.cs b/ConsoleInteractive/ConsoleInteractive/ConsoleBuffer.cs index 5142b12..594e3e3 100644 --- a/ConsoleInteractive/ConsoleInteractive/ConsoleBuffer.cs +++ b/ConsoleInteractive/ConsoleInteractive/ConsoleBuffer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using System.Threading; @@ -99,7 +99,7 @@ public static class ConsoleBuffer { /// internal static int UserInputBufferMaxLength { get { - int result = Console.BufferWidth - 1 - PrefixTotalLength; + int result = InternalContext.SafeBufferWidth - 1 - PrefixTotalLength; return result > 0 ? result : 0; } } @@ -326,13 +326,16 @@ internal static string FlushBuffer() { /// Does not clear the internal buffer. /// internal static void ClearVisibleUserInput(int startPos = 0) { + if (!InternalContext.IsInteractiveConsole) return; lock (InternalContext.WriteLock) { - if (startPos < Console.BufferWidth) { - Console.CursorLeft = startPos; - Console.Write(new string(' ', Math.Max(0, - PrefixTotalLength + Math.Min(UserInputBuffer.Length - BufferOutputAnchor, UserInputBufferMaxLength) - startPos))); - } - Console.CursorLeft = 0; + try { + if (startPos < Console.BufferWidth) { + Console.CursorLeft = startPos; + Console.Write(new string(' ', Math.Max(0, + PrefixTotalLength + Math.Min(UserInputBuffer.Length - BufferOutputAnchor, UserInputBufferMaxLength) - startPos))); + } + Console.CursorLeft = 0; + } catch { } } } @@ -360,10 +363,10 @@ internal static void RedrawInputArea(bool RedrawAll = false) { if (InternalContext.SuppressInput) return; - if (Console.IsOutputRedirected || !ConsoleReader.DisplayUesrInput) + if (!InternalContext.IsInteractiveConsole || Console.IsOutputRedirected || !ConsoleReader.DisplayUesrInput) return; - StringBuilder sb = new(Console.BufferWidth); + StringBuilder sb = new(InternalContext.SafeBufferWidth); int bufMaxLen = UserInputBufferMaxLength; int leftCursorPos; @@ -412,16 +415,19 @@ internal static void RedrawInputArea(bool RedrawAll = false) { } if (startIndex == sb.Length) { - lock (InternalContext.WriteLock) - Console.CursorLeft = leftCursorPos; + lock (InternalContext.WriteLock) { + try { Console.CursorLeft = leftCursorPos; } catch { } + } } else { lock (InternalContext.WriteLock) { - InternalContext.SetCursorVisible(false); - Console.CursorLeft = startIndex; - Console.Write(sb.ToString(startIndex, sb.Length - startIndex)); - if (leftCursorPos != sb.Length) - Console.CursorLeft = leftCursorPos; - InternalContext.SetCursorVisible(true); + try { + InternalContext.SetCursorVisible(false); + Console.CursorLeft = startIndex; + Console.Write(sb.ToString(startIndex, sb.Length - startIndex)); + if (leftCursorPos != sb.Length) + Console.CursorLeft = leftCursorPos; + InternalContext.SetCursorVisible(true); + } catch { } } } } diff --git a/ConsoleInteractive/ConsoleInteractive/ConsoleSuggestion.cs b/ConsoleInteractive/ConsoleInteractive/ConsoleSuggestion.cs index 3dfd10a..f6c9573 100644 --- a/ConsoleInteractive/ConsoleInteractive/ConsoleSuggestion.cs +++ b/ConsoleInteractive/ConsoleInteractive/ConsoleSuggestion.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; @@ -27,7 +27,7 @@ public static class ConsoleSuggestion { private static Suggestion[] Suggestions = Array.Empty(); public static void UpdateSuggestions(Suggestion[] Suggestions, Tuple range) { - if (Console.IsOutputRedirected) { + if (Console.IsOutputRedirected || !InternalContext.IsInteractiveConsole) { ClearSuggestions(); return; } @@ -43,7 +43,7 @@ public static void UpdateSuggestions(Suggestion[] Suggestions, Tuple r return; } - if (Console.BufferWidth < maxLength) { + if (InternalContext.SafeBufferWidth < maxLength) { ClearSuggestions(); return; } @@ -348,10 +348,11 @@ private enum ColorType { Reset, Normal, NormalBg, Highlight, HighlightBg, Toolti private static readonly BgMessageBuffer[] BgBuffer = new BgMessageBuffer[MaxValueOfMaxSuggestionCount]; internal static void DrawSuggestionPopup(bool refreshMsgBuf = true, int bufWidth = -1) { + if (!InternalContext.IsInteractiveConsole) return; BgMessageBuffer[] messageBuffers = Array.Empty(); int curBufIdx = -1, nextMessageIdx = 0; lock (InternalContext.WriteLock) { - if (bufWidth == -1) bufWidth = Console.BufferWidth; + if (bufWidth == -1) bufWidth = InternalContext.SafeBufferWidth; if (PopupWidth > bufWidth) return; (int left, int top) = Console.GetCursorPosition(); LastDrawStartPos = GetDrawStartPos(bufWidth); @@ -374,9 +375,10 @@ internal static void DrawSuggestionPopup(bool refreshMsgBuf = true, int bufWidth } internal static void ClearSuggestionPopup(int linesAdded = 0, int bufWidth = -1) { + if (!InternalContext.IsInteractiveConsole) return; int DisplaySuggestionsCnt = Math.Min(MaxSuggestionCount, Suggestions.Length); lock (InternalContext.WriteLock) { - if (bufWidth == -1) bufWidth = Console.BufferWidth; + if (bufWidth == -1) bufWidth = InternalContext.SafeBufferWidth; int drawStartPos = GetDrawStartPos(bufWidth); (int left, int top) = Console.GetCursorPosition(); InternalContext.SetCursorVisible(false); @@ -390,6 +392,7 @@ internal static void ClearSuggestionPopup(int linesAdded = 0, int bufWidth = -1) } internal static void RedrawOnArrowKey(int offset) { + if (!InternalContext.IsInteractiveConsole) return; lock (InternalContext.WriteLock) { (int left, int top) = Console.GetCursorPosition(); InternalContext.SetCursorVisible(false); @@ -404,8 +407,9 @@ internal static void RedrawOnArrowKey(int offset) { } internal static void RedrawOnTab() { + if (!InternalContext.IsInteractiveConsole) return; lock (InternalContext.WriteLock) { - int bufWidth = Console.BufferWidth; + int bufWidth = InternalContext.SafeBufferWidth; if (GetDrawStartPos(bufWidth) != LastDrawStartPos) { ClearSuggestionPopup(bufWidth: bufWidth); DrawSuggestionPopup(refreshMsgBuf: true, bufWidth: bufWidth); diff --git a/ConsoleInteractive/ConsoleInteractive/ConsoleWriter.cs b/ConsoleInteractive/ConsoleInteractive/ConsoleWriter.cs index 6ddcef1..91633b4 100644 --- a/ConsoleInteractive/ConsoleInteractive/ConsoleWriter.cs +++ b/ConsoleInteractive/ConsoleInteractive/ConsoleWriter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; @@ -14,9 +14,10 @@ public static class ConsoleWriter { public static void Init() { SetWindowsConsoleAnsi(); - if (!Console.IsOutputRedirected) - Console.Clear(); - if (InDocker) + if (!Console.IsOutputRedirected && InternalContext.IsInteractiveConsole) { + try { Console.Clear(); } catch { } + } + if (InDocker || !InternalContext.IsInteractiveConsole) BackendWriter = new FallbackWriter(); } @@ -58,12 +59,12 @@ internal class InternalWriter : IWriter { /// Gets the number of lines and the width of the first line of the message. /// private Tuple GetLineCountInTerminal(string value) { - if (Console.IsOutputRedirected) + if (Console.IsOutputRedirected || !InternalContext.IsInteractiveConsole) return new(0, 0); bool escape = false; int lineCnt = 0, cursorPos = 0, firstLineLength = -1; - int bufWidth = Console.BufferWidth; + int bufWidth = InternalContext.SafeBufferWidth; foreach (char c in value) { if (!escape && c == '\u001B') { escape = true; @@ -129,17 +130,18 @@ private void Write(string value, List>? colors = lock (InternalContext.WriteLock) { ConsoleSuggestion.BeforeWrite(value, linesAdded); - if (!Console.IsOutputRedirected) { - if (InternalContext.BufferInitialized) - ConsoleBuffer.ClearVisibleUserInput(startPos: firstLineLength); - else - Console.CursorLeft = 0; + if (!Console.IsOutputRedirected && InternalContext.IsInteractiveConsole) { + try { + if (InternalContext.BufferInitialized) + ConsoleBuffer.ClearVisibleUserInput(startPos: firstLineLength); + else + Console.CursorLeft = 0; + } catch { } } WriteConsole(value, colors); - if (!Console.IsOutputRedirected) { - // Only redraw if we have a buffer initialized. + if (!Console.IsOutputRedirected && InternalContext.IsInteractiveConsole) { if (InternalContext.BufferInitialized) ConsoleBuffer.RedrawInputArea(RedrawAll: true); } diff --git a/ConsoleInteractive/ConsoleInteractive/InternalContext.cs b/ConsoleInteractive/ConsoleInteractive/InternalContext.cs index 000d670..ff1e3f4 100644 --- a/ConsoleInteractive/ConsoleInteractive/InternalContext.cs +++ b/ConsoleInteractive/ConsoleInteractive/InternalContext.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Text.RegularExpressions; namespace ConsoleInteractive { @@ -13,6 +13,28 @@ internal static partial class InternalContext { internal static volatile bool _suppressInput = false; internal static volatile bool BufferInitialized = false; + internal static readonly bool IsInteractiveConsole = DetectInteractiveConsole(); + + private static bool DetectInteractiveConsole() { + if (Console.IsInputRedirected || Console.IsOutputRedirected) + return false; + try { + _ = Console.BufferWidth; + _ = Console.KeyAvailable; + return true; + } catch { + return false; + } + } + + internal static int SafeBufferWidth { + get { + if (!IsInteractiveConsole) return 120; + try { return Console.BufferWidth; } + catch { return 120; } + } + } + internal static bool SuppressInput { get { return _suppressInput; } set { @@ -26,9 +48,11 @@ internal static bool SuppressInput { } internal static void SetCursorVisible(bool visible) { + if (!IsInteractiveConsole) return; + // It's useful to have the cursor visible in debug situations #if !DEBUG - Console.CursorVisible = visible; + try { Console.CursorVisible = visible; } catch { } #endif }