From fcf548223421f2692c66a2cd5c77ab076f54ef52 Mon Sep 17 00:00:00 2001 From: "Dan Thompson (SBS)" Date: Mon, 24 Jul 2023 23:24:07 -0700 Subject: [PATCH] Work around InvalidOperationExceptions from Console API Addresses #3744 There is a problem with the .NET Console API, described in this Issue: https://github.com/dotnet/runtime/issues/88697 This change works around the problem by handling the InvalidOperationException that might spuriously fly out of KeyAvailable and ReadKey (with a limited number of retries, in case there is something *else* pathological going on). --- PSReadLine/ConsoleLib.cs | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/PSReadLine/ConsoleLib.cs b/PSReadLine/ConsoleLib.cs index 7cc53b341..dc1d1b455 100644 --- a/PSReadLine/ConsoleLib.cs +++ b/PSReadLine/ConsoleLib.cs @@ -113,8 +113,40 @@ public Encoding OutputEncoding set { try { Console.OutputEncoding = value; } catch { } } } - public ConsoleKeyInfo ReadKey() => _readKeyMethod.Value(true); - public bool KeyAvailable => Console.KeyAvailable; + private static T _TryIgnoreIOE(Func f) + { + int triesLeft = 10; + while (true) + { + try + { + triesLeft--; + return f(); + } + catch (InvalidOperationException) + { + // Ignore it. An IOE could be thrown if the "application does not have a + // console or when console input has been redirected"... but we don't + // expect PSReadLine to be involved in such a situation. So we are + // actually probably running into this Issue (wherein another process + // attached to the same console terminated at just the right/wrong time): + // + // https://github.com/dotnet/runtime/issues/88697 + // + // In the event there is some *other* pathological situation + // happening, we have limited the number of times we will + // swallow/retry this exception/operation. + + if (triesLeft <= 0) + { + throw; + } + } + } + } + + public ConsoleKeyInfo ReadKey() => _TryIgnoreIOE(() => _readKeyMethod.Value(true)); + public bool KeyAvailable => _TryIgnoreIOE(() => Console.KeyAvailable); public void SetWindowPosition(int left, int top) => Console.SetWindowPosition(left, top); public void SetCursorPosition(int left, int top) => Console.SetCursorPosition(left, top); public virtual void Write(string value) => Console.Write(value);