瀏覽代碼

Merge pull request #173 from tig/tznind-ansi-parser

Code review comments and cleanup
Thomas Nind 8 月之前
父節點
當前提交
21f0cc1be8
共有 43 個文件被更改,包括 299 次插入245 次删除
  1. 1 0
      Terminal.Gui/ConsoleDrivers/AnsiEscapeSequenceRequest.cs
  2. 15 31
      Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiRequestScheduler.cs
  3. 102 94
      Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiResponseParser.cs
  4. 1 1
      Terminal.Gui/ConsoleDrivers/AnsiResponseParser/IAnsiResponseParser.cs
  5. 21 0
      Terminal.Gui/ConsoleDrivers/AnsiResponseParser/ReasonCannotSend.cs
  6. 5 5
      Terminal.Gui/ConsoleDrivers/AnsiResponseParser/StringHeld.cs
  7. 4 0
      Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs
  8. 7 0
      Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
  9. 1 0
      Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs
  10. 48 20
      Terminal.Gui/ConsoleDrivers/IConsoleDriver.cs
  11. 2 0
      Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs
  12. 1 0
      Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs
  13. 0 0
      Terminal.Gui/Drawing/Color/AnsiColorCode.cs
  14. 0 0
      Terminal.Gui/Drawing/Color/Color.ColorExtensions.cs
  15. 0 0
      Terminal.Gui/Drawing/Color/Color.ColorName.cs
  16. 0 0
      Terminal.Gui/Drawing/Color/Color.ColorParseException.cs
  17. 0 0
      Terminal.Gui/Drawing/Color/Color.Formatting.cs
  18. 0 0
      Terminal.Gui/Drawing/Color/Color.Operators.cs
  19. 0 0
      Terminal.Gui/Drawing/Color/Color.cs
  20. 0 0
      Terminal.Gui/Drawing/Color/ColorEventArgs.cs
  21. 0 0
      Terminal.Gui/Drawing/Color/ColorModel.cs
  22. 0 0
      Terminal.Gui/Drawing/Color/ColorQuantizer.cs
  23. 0 0
      Terminal.Gui/Drawing/Color/ColorScheme.Colors.cs
  24. 0 0
      Terminal.Gui/Drawing/Color/ColorScheme.cs
  25. 0 0
      Terminal.Gui/Drawing/Color/ColorStrings.cs
  26. 0 0
      Terminal.Gui/Drawing/Color/IColorDistance.cs
  27. 0 0
      Terminal.Gui/Drawing/Color/IColorNameResolver.cs
  28. 0 0
      Terminal.Gui/Drawing/Color/ICustomColorFormatter.cs
  29. 0 0
      Terminal.Gui/Drawing/Color/W3CColors.cs
  30. 0 0
      Terminal.Gui/Drawing/LineCanvas/IntersectionDefinition.cs
  31. 0 0
      Terminal.Gui/Drawing/LineCanvas/IntersectionRuneType.cs
  32. 0 0
      Terminal.Gui/Drawing/LineCanvas/IntersectionType.cs
  33. 0 0
      Terminal.Gui/Drawing/LineCanvas/LineCanvas.cs
  34. 0 0
      Terminal.Gui/Drawing/LineCanvas/LineStyle.cs
  35. 0 0
      Terminal.Gui/Drawing/LineCanvas/StraightLine.cs
  36. 0 0
      Terminal.Gui/Drawing/LineCanvas/StraightLineExtensions.cs
  37. 4 4
      Terminal.Gui/Drawing/Sixel/SixelEncoder.cs
  38. 61 57
      Terminal.Gui/Drawing/Sixel/SixelSupportDetector.cs
  39. 1 1
      Terminal.Gui/Drawing/Sixel/SixelSupportResult.cs
  40. 0 0
      Terminal.Gui/Drawing/Sixel/SixelToRender.cs
  41. 14 16
      UICatalog/Scenarios/AnsiRequestsScenario.cs
  42. 11 14
      UICatalog/Scenarios/Images.cs
  43. 0 2
      UnitTests/ConsoleDrivers/AnsiResponseParserTests.cs

+ 1 - 0
Terminal.Gui/ConsoleDrivers/AnsiEscapeSequenceRequest.cs

@@ -16,6 +16,7 @@ public class AnsiEscapeSequenceRequest
     /// </summary>
     /// </summary>
     public required string Request { get; init; }
     public required string Request { get; init; }
 
 
+    // BUGBUG: Nullable issue
     /// <summary>
     /// <summary>
     ///     Invoked when the console responds with an ANSI response code that matches the
     ///     Invoked when the console responds with an ANSI response code that matches the
     ///     <see cref="Terminator"/>
     ///     <see cref="Terminator"/>

+ 15 - 31
Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiRequestScheduler.cs

@@ -14,8 +14,8 @@ public class AnsiRequestScheduler
     private readonly IAnsiResponseParser _parser;
     private readonly IAnsiResponseParser _parser;
 
 
     /// <summary>
     /// <summary>
-    /// Function for returning the current time. Use in unit tests to
-    /// ensure repeatable tests.
+    ///     Function for returning the current time. Use in unit tests to
+    ///     ensure repeatable tests.
     /// </summary>
     /// </summary>
     internal Func<DateTime> Now { get; set; }
     internal Func<DateTime> Now { get; set; }
 
 
@@ -54,6 +54,11 @@ public class AnsiRequestScheduler
 
 
     private readonly DateTime _lastRun;
     private readonly DateTime _lastRun;
 
 
+    /// <summary>
+    ///     Creates a new instance.
+    /// </summary>
+    /// <param name="parser"></param>
+    /// <param name="now"></param>
     public AnsiRequestScheduler (IAnsiResponseParser parser, Func<DateTime>? now = null)
     public AnsiRequestScheduler (IAnsiResponseParser parser, Func<DateTime>? now = null)
     {
     {
         _parser = parser;
         _parser = parser;
@@ -67,11 +72,9 @@ public class AnsiRequestScheduler
     /// </summary>
     /// </summary>
     /// <param name="request"></param>
     /// <param name="request"></param>
     /// <returns><see langword="true"/> if request was sent immediately. <see langword="false"/> if it was queued.</returns>
     /// <returns><see langword="true"/> if request was sent immediately. <see langword="false"/> if it was queued.</returns>
-    public bool SendOrSchedule (AnsiEscapeSequenceRequest request)
-    {
-        return SendOrSchedule (request, true);
-    }
-    private bool SendOrSchedule (AnsiEscapeSequenceRequest request,bool addToQueue)
+    public bool SendOrSchedule (AnsiEscapeSequenceRequest request) { return SendOrSchedule (request, true); }
+
+    private bool SendOrSchedule (AnsiEscapeSequenceRequest request, bool addToQueue)
     {
     {
         if (CanSend (request, out ReasonCannotSend reason))
         if (CanSend (request, out ReasonCannotSend reason))
         {
         {
@@ -105,13 +108,13 @@ public class AnsiRequestScheduler
 
 
     private void EvictStaleRequests ()
     private void EvictStaleRequests ()
     {
     {
-        foreach (var stale in _lastSend.Where (v => IsStale (v.Value)).Select (k => k.Key))
+        foreach (string stale in _lastSend.Where (v => IsStale (v.Value)).Select (k => k.Key))
         {
         {
             EvictStaleRequests (stale);
             EvictStaleRequests (stale);
         }
         }
     }
     }
 
 
-    private bool IsStale (DateTime dt) => Now () - dt > _staleTimeout;
+    private bool IsStale (DateTime dt) { return Now () - dt > _staleTimeout; }
 
 
     /// <summary>
     /// <summary>
     ///     Looks to see if the last time we sent <paramref name="withTerminator"/>
     ///     Looks to see if the last time we sent <paramref name="withTerminator"/>
@@ -155,7 +158,7 @@ public class AnsiRequestScheduler
         }
         }
 
 
         // Get oldest request
         // Get oldest request
-        Tuple<AnsiEscapeSequenceRequest, DateTime>? opportunity = _queuedRequests.MinBy (r=>r.Item2);
+        Tuple<AnsiEscapeSequenceRequest, DateTime>? opportunity = _queuedRequests.MinBy (r => r.Item2);
 
 
         if (opportunity != null)
         if (opportunity != null)
         {
         {
@@ -163,6 +166,7 @@ public class AnsiRequestScheduler
             if (SendOrSchedule (opportunity.Item1, false))
             if (SendOrSchedule (opportunity.Item1, false))
             {
             {
                 _queuedRequests.Remove (opportunity);
                 _queuedRequests.Remove (opportunity);
+
                 return true;
                 return true;
             }
             }
         }
         }
@@ -172,7 +176,6 @@ public class AnsiRequestScheduler
         return false;
         return false;
     }
     }
 
 
-
     private void Send (AnsiEscapeSequenceRequest r)
     private void Send (AnsiEscapeSequenceRequest r)
     {
     {
         _lastSend.AddOrUpdate (r.Terminator, _ => Now (), (_, _) => Now ());
         _lastSend.AddOrUpdate (r.Terminator, _ => Now (), (_, _) => Now ());
@@ -210,23 +213,4 @@ public class AnsiRequestScheduler
 
 
         return false;
         return false;
     }
     }
-}
-
-internal enum ReasonCannotSend
-{
-    /// <summary>
-    ///     No reason given.
-    /// </summary>
-    None = 0,
-
-    /// <summary>
-    ///     The parser is already waiting for a request to complete with the given terminator.
-    /// </summary>
-    OutstandingRequest,
-
-    /// <summary>
-    ///     There have been too many requests sent recently, new requests will be put into
-    ///     queue to prevent console becoming unresponsive.
-    /// </summary>
-    TooManyRequests
-}
+}

+ 102 - 94
Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiResponseParser.cs

@@ -4,29 +4,29 @@ namespace Terminal.Gui;
 
 
 internal abstract class AnsiResponseParserBase : IAnsiResponseParser
 internal abstract class AnsiResponseParserBase : IAnsiResponseParser
 {
 {
-    protected object lockExpectedResponses = new ();
+    protected object _lockExpectedResponses = new ();
 
 
-    protected object lockState = new ();
+    protected object _lockState = new ();
 
 
     /// <summary>
     /// <summary>
     ///     Responses we are expecting to come in.
     ///     Responses we are expecting to come in.
     /// </summary>
     /// </summary>
-    protected readonly List<AnsiResponseExpectation> expectedResponses = new ();
+    protected readonly List<AnsiResponseExpectation> _expectedResponses = [];
 
 
     /// <summary>
     /// <summary>
     ///     Collection of responses that we <see cref="StopExpecting"/>.
     ///     Collection of responses that we <see cref="StopExpecting"/>.
     /// </summary>
     /// </summary>
-    protected readonly List<AnsiResponseExpectation> lateResponses = new ();
+    protected readonly List<AnsiResponseExpectation> _lateResponses = [];
 
 
     /// <summary>
     /// <summary>
     ///     Responses that you want to look out for that will come in continuously e.g. mouse events.
     ///     Responses that you want to look out for that will come in continuously e.g. mouse events.
     ///     Key is the terminator.
     ///     Key is the terminator.
     /// </summary>
     /// </summary>
-    protected readonly List<AnsiResponseExpectation> persistentExpectations = new ();
+    protected readonly List<AnsiResponseExpectation> _persistentExpectations = [];
 
 
     private AnsiResponseParserState _state = AnsiResponseParserState.Normal;
     private AnsiResponseParserState _state = AnsiResponseParserState.Normal;
 
 
-    /// <inheritdoc />
+    /// <inheritdoc/>
     public AnsiResponseParserState State
     public AnsiResponseParserState State
     {
     {
         get => _state;
         get => _state;
@@ -37,7 +37,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
         }
         }
     }
     }
 
 
-    protected readonly IHeld heldContent;
+    protected readonly IHeld _heldContent;
 
 
     /// <summary>
     /// <summary>
     ///     When <see cref="State"/> was last changed.
     ///     When <see cref="State"/> was last changed.
@@ -48,8 +48,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
     // see CSI in https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s
     // see CSI in https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s
     // No - N or O
     // No - N or O
     protected readonly HashSet<char> _knownTerminators = new (
     protected readonly HashSet<char> _knownTerminators = new (
-                                                              new []
-                                                              {
+                                                              [
                                                                   '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
                                                                   '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
 
 
                                                                   // No - N or O
                                                                   // No - N or O
@@ -58,14 +57,18 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
                                                                   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
                                                                   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
                                                                   'l', 'm', 'n',
                                                                   'l', 'm', 'n',
                                                                   'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
                                                                   'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
-                                                              });
+                                                              ]);
 
 
-    protected AnsiResponseParserBase (IHeld heldContent) { this.heldContent = heldContent; }
+    protected AnsiResponseParserBase (IHeld heldContent) { _heldContent = heldContent; }
 
 
     protected void ResetState ()
     protected void ResetState ()
     {
     {
         State = AnsiResponseParserState.Normal;
         State = AnsiResponseParserState.Normal;
-        heldContent.ClearHeld ();
+
+        lock (_lockState)
+        {
+            _heldContent.ClearHeld ();
+        }
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -87,7 +90,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
         int inputLength
         int inputLength
     )
     )
     {
     {
-        lock (lockState)
+        lock (_lockState)
         {
         {
             ProcessInputBaseImpl (getCharAtIndex, getObjectAtIndex, appendOutput, inputLength);
             ProcessInputBaseImpl (getCharAtIndex, getObjectAtIndex, appendOutput, inputLength);
         }
         }
@@ -116,7 +119,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
                     {
                     {
                         // Escape character detected, move to ExpectingBracket state
                         // Escape character detected, move to ExpectingBracket state
                         State = AnsiResponseParserState.ExpectingBracket;
                         State = AnsiResponseParserState.ExpectingBracket;
-                        heldContent.AddToHeld (currentObj); // Hold the escape character
+                        _heldContent.AddToHeld (currentObj); // Hold the escape character
                     }
                     }
                     else
                     else
                     {
                     {
@@ -131,13 +134,13 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
                     {
                     {
                         // Second escape so we must release first
                         // Second escape so we must release first
                         ReleaseHeld (appendOutput, AnsiResponseParserState.ExpectingBracket);
                         ReleaseHeld (appendOutput, AnsiResponseParserState.ExpectingBracket);
-                        heldContent.AddToHeld (currentObj); // Hold the new escape
+                        _heldContent.AddToHeld (currentObj); // Hold the new escape
                     }
                     }
                     else if (currentChar == '[')
                     else if (currentChar == '[')
                     {
                     {
                         // Detected '[', transition to InResponse state
                         // Detected '[', transition to InResponse state
                         State = AnsiResponseParserState.InResponse;
                         State = AnsiResponseParserState.InResponse;
-                        heldContent.AddToHeld (currentObj); // Hold the '['
+                        _heldContent.AddToHeld (currentObj); // Hold the '['
                     }
                     }
                     else
                     else
                     {
                     {
@@ -149,7 +152,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
                     break;
                     break;
 
 
                 case AnsiResponseParserState.InResponse:
                 case AnsiResponseParserState.InResponse:
-                    heldContent.AddToHeld (currentObj);
+                    _heldContent.AddToHeld (currentObj);
 
 
                     // Check if the held content should be released
                     // Check if the held content should be released
                     if (ShouldReleaseHeldContent ())
                     if (ShouldReleaseHeldContent ())
@@ -166,73 +169,76 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
 
 
     private void ReleaseHeld (Action<object> appendOutput, AnsiResponseParserState newState = AnsiResponseParserState.Normal)
     private void ReleaseHeld (Action<object> appendOutput, AnsiResponseParserState newState = AnsiResponseParserState.Normal)
     {
     {
-        foreach (object o in heldContent.HeldToObjects ())
+        foreach (object o in _heldContent.HeldToObjects ())
         {
         {
             appendOutput (o);
             appendOutput (o);
         }
         }
 
 
         State = newState;
         State = newState;
-        heldContent.ClearHeld ();
+        _heldContent.ClearHeld ();
     }
     }
 
 
     // Common response handler logic
     // Common response handler logic
     protected bool ShouldReleaseHeldContent ()
     protected bool ShouldReleaseHeldContent ()
     {
     {
-        string cur = heldContent.HeldToString ();
-
-        lock (lockExpectedResponses)
+        lock (_lockState)
         {
         {
-            // Look for an expected response for what is accumulated so far (since Esc)
-            if (MatchResponse (
-                               cur,
-                               expectedResponses,
-                               true,
-                               true))
-            {
-                return false;
-            }
+            string cur = _heldContent.HeldToString ();
 
 
-            // Also try looking for late requests - in which case we do not invoke but still swallow content to avoid corrupting downstream
-            if (MatchResponse (
-                               cur,
-                               lateResponses,
-                               false,
-                               true))
+            lock (_lockExpectedResponses)
             {
             {
-                return false;
+                // Look for an expected response for what is accumulated so far (since Esc)
+                if (MatchResponse (
+                                   cur,
+                                   _expectedResponses,
+                                   true,
+                                   true))
+                {
+                    return false;
+                }
+
+                // Also try looking for late requests - in which case we do not invoke but still swallow content to avoid corrupting downstream
+                if (MatchResponse (
+                                   cur,
+                                   _lateResponses,
+                                   false,
+                                   true))
+                {
+                    return false;
+                }
+
+                // Look for persistent requests
+                if (MatchResponse (
+                                   cur,
+                                   _persistentExpectations,
+                                   true,
+                                   false))
+                {
+                    return false;
+                }
             }
             }
 
 
-            // Look for persistent requests
-            if (MatchResponse (
-                               cur,
-                               persistentExpectations,
-                               true,
-                               false))
+            // Finally if it is a valid ansi response but not one we are expect (e.g. its mouse activity)
+            // then we can release it back to input processing stream
+            if (_knownTerminators.Contains (cur.Last ()) && cur.StartsWith (EscSeqUtils.CSI))
             {
             {
-                return false;
-            }
-        }
+                // We have found a terminator so bail
+                State = AnsiResponseParserState.Normal;
 
 
-        // Finally if it is a valid ansi response but not one we are expect (e.g. its mouse activity)
-        // then we can release it back to input processing stream
-        if (_knownTerminators.Contains (cur.Last ()) && cur.StartsWith (EscSeqUtils.CSI))
-        {
-            // We have found a terminator so bail
-            State = AnsiResponseParserState.Normal;
+                // Maybe swallow anyway if user has custom delegate
+                bool swallow = ShouldSwallowUnexpectedResponse ();
 
 
-            // Maybe swallow anyway if user has custom delegate
-            bool swallow = ShouldSwallowUnexpectedResponse ();
+                if (swallow)
+                {
+                    _heldContent.ClearHeld ();
 
 
-            if (swallow)
-            {
-                heldContent.ClearHeld ();
+                    // Do not send back to input stream
+                    return false;
+                }
 
 
-                // Do not send back to input stream
-                return false;
+                // Do release back to input stream
+                return true;
             }
             }
-
-            // Do release back to input stream
-            return true;
         }
         }
 
 
         return false; // Continue accumulating
         return false; // Continue accumulating
@@ -241,7 +247,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
     /// <summary>
     /// <summary>
     ///     <para>
     ///     <para>
     ///         When overriden in a derived class, indicates whether the unexpected response
     ///         When overriden in a derived class, indicates whether the unexpected response
-    ///         currently in <see cref="heldContent"/> should be released or swallowed.
+    ///         currently in <see cref="_heldContent"/> should be released or swallowed.
     ///         Use this to enable default event for escape codes.
     ///         Use this to enable default event for escape codes.
     ///     </para>
     ///     </para>
     ///     <remarks>
     ///     <remarks>
@@ -261,7 +267,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
         {
         {
             if (invokeCallback)
             if (invokeCallback)
             {
             {
-                matchingResponse.Response.Invoke (heldContent);
+                matchingResponse.Response.Invoke (_heldContent);
             }
             }
 
 
             ResetState ();
             ResetState ();
@@ -278,17 +284,17 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
     }
     }
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
-    public void ExpectResponse (string terminator, Action<string> response,Action? abandoned, bool persistent)
+    public void ExpectResponse (string terminator, Action<string> response, Action? abandoned, bool persistent)
     {
     {
-        lock (lockExpectedResponses)
+        lock (_lockExpectedResponses)
         {
         {
             if (persistent)
             if (persistent)
             {
             {
-                persistentExpectations.Add (new (terminator, h => response.Invoke (h.HeldToString ()), abandoned));
+                _persistentExpectations.Add (new (terminator, h => response.Invoke (h.HeldToString ()), abandoned));
             }
             }
             else
             else
             {
             {
-                expectedResponses.Add (new (terminator, h => response.Invoke (h.HeldToString ()), abandoned));
+                _expectedResponses.Add (new (terminator, h => response.Invoke (h.HeldToString ()), abandoned));
             }
             }
         }
         }
     }
     }
@@ -296,36 +302,36 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
     /// <inheritdoc/>
     /// <inheritdoc/>
     public bool IsExpecting (string terminator)
     public bool IsExpecting (string terminator)
     {
     {
-        lock (lockExpectedResponses)
+        lock (_lockExpectedResponses)
         {
         {
             // If any of the new terminator matches any existing terminators characters it's a collision so true.
             // If any of the new terminator matches any existing terminators characters it's a collision so true.
-            return expectedResponses.Any (r => r.Terminator.Intersect (terminator).Any ());
+            return _expectedResponses.Any (r => r.Terminator.Intersect (terminator).Any ());
         }
         }
     }
     }
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
     public void StopExpecting (string terminator, bool persistent)
     public void StopExpecting (string terminator, bool persistent)
     {
     {
-        lock (lockExpectedResponses)
+        lock (_lockExpectedResponses)
         {
         {
             if (persistent)
             if (persistent)
             {
             {
-                AnsiResponseExpectation [] removed = persistentExpectations.Where (r => r.Matches (terminator)).ToArray ();
+                AnsiResponseExpectation [] removed = _persistentExpectations.Where (r => r.Matches (terminator)).ToArray ();
 
 
-                foreach (var toRemove in removed)
+                foreach (AnsiResponseExpectation toRemove in removed)
                 {
                 {
-                    persistentExpectations.Remove (toRemove);
+                    _persistentExpectations.Remove (toRemove);
                     toRemove.Abandoned?.Invoke ();
                     toRemove.Abandoned?.Invoke ();
                 }
                 }
             }
             }
             else
             else
             {
             {
-                AnsiResponseExpectation [] removed = expectedResponses.Where (r => r.Terminator == terminator).ToArray ();
+                AnsiResponseExpectation [] removed = _expectedResponses.Where (r => r.Terminator == terminator).ToArray ();
 
 
                 foreach (AnsiResponseExpectation r in removed)
                 foreach (AnsiResponseExpectation r in removed)
                 {
                 {
-                    expectedResponses.Remove (r);
-                    lateResponses.Add (r);
+                    _expectedResponses.Remove (r);
+                    _lateResponses.Add (r);
                     r.Abandoned?.Invoke ();
                     r.Abandoned?.Invoke ();
                 }
                 }
             }
             }
@@ -333,10 +339,8 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
     }
     }
 }
 }
 
 
-internal class AnsiResponseParser<T> : AnsiResponseParserBase
+internal class AnsiResponseParser<T> () : AnsiResponseParserBase (new GenericHeld<T> ())
 {
 {
-    public AnsiResponseParser () : base (new GenericHeld<T> ()) { }
-
     /// <inheritdoc cref="AnsiResponseParser.UnknownResponseHandler"/>
     /// <inheritdoc cref="AnsiResponseParser.UnknownResponseHandler"/>
     public Func<IEnumerable<Tuple<char, T>>, bool> UnexpectedResponseHandler { get; set; } = _ => false;
     public Func<IEnumerable<Tuple<char, T>>, bool> UnexpectedResponseHandler { get; set; } = _ => false;
 
 
@@ -353,10 +357,10 @@ internal class AnsiResponseParser<T> : AnsiResponseParserBase
         return output;
         return output;
     }
     }
 
 
-    public Tuple<char, T>[] Release ()
+    public Tuple<char, T> [] Release ()
     {
     {
         // Lock in case Release is called from different Thread from parse
         // Lock in case Release is called from different Thread from parse
-        lock (lockState)
+        lock (_lockState)
         {
         {
             Tuple<char, T> [] result = HeldToEnumerable ().ToArray ();
             Tuple<char, T> [] result = HeldToEnumerable ().ToArray ();
 
 
@@ -366,7 +370,7 @@ internal class AnsiResponseParser<T> : AnsiResponseParserBase
         }
         }
     }
     }
 
 
-    private IEnumerable<Tuple<char, T>> HeldToEnumerable () { return (IEnumerable<Tuple<char, T>>)heldContent.HeldToObjects (); }
+    private IEnumerable<Tuple<char, T>> HeldToEnumerable () { return (IEnumerable<Tuple<char, T>>)_heldContent.HeldToObjects (); }
 
 
     /// <summary>
     /// <summary>
     ///     'Overload' for specifying an expectation that requires the metadata as well as characters. Has
     ///     'Overload' for specifying an expectation that requires the metadata as well as characters. Has
@@ -376,17 +380,17 @@ internal class AnsiResponseParser<T> : AnsiResponseParserBase
     /// <param name="response"></param>
     /// <param name="response"></param>
     /// <param name="abandoned"></param>
     /// <param name="abandoned"></param>
     /// <param name="persistent"></param>
     /// <param name="persistent"></param>
-    public void ExpectResponseT (string terminator, Action<IEnumerable<Tuple<char, T>>> response,Action? abandoned, bool persistent)
+    public void ExpectResponseT (string terminator, Action<IEnumerable<Tuple<char, T>>> response, Action? abandoned, bool persistent)
     {
     {
-        lock (lockExpectedResponses)
+        lock (_lockExpectedResponses)
         {
         {
             if (persistent)
             if (persistent)
             {
             {
-                persistentExpectations.Add (new (terminator, h => response.Invoke (HeldToEnumerable ()), abandoned));
+                _persistentExpectations.Add (new (terminator, h => response.Invoke (HeldToEnumerable ()), abandoned));
             }
             }
             else
             else
             {
             {
-                expectedResponses.Add (new (terminator, h => response.Invoke (HeldToEnumerable ()), abandoned));
+                _expectedResponses.Add (new (terminator, h => response.Invoke (HeldToEnumerable ()), abandoned));
             }
             }
         }
         }
     }
     }
@@ -395,7 +399,7 @@ internal class AnsiResponseParser<T> : AnsiResponseParserBase
     protected override bool ShouldSwallowUnexpectedResponse () { return UnexpectedResponseHandler.Invoke (HeldToEnumerable ()); }
     protected override bool ShouldSwallowUnexpectedResponse () { return UnexpectedResponseHandler.Invoke (HeldToEnumerable ()); }
 }
 }
 
 
-internal class AnsiResponseParser : AnsiResponseParserBase
+internal class AnsiResponseParser () : AnsiResponseParserBase (new StringHeld ())
 {
 {
     /// <summary>
     /// <summary>
     ///     <para>
     ///     <para>
@@ -410,8 +414,6 @@ internal class AnsiResponseParser : AnsiResponseParserBase
     /// </summary>
     /// </summary>
     public Func<string, bool> UnknownResponseHandler { get; set; } = _ => false;
     public Func<string, bool> UnknownResponseHandler { get; set; } = _ => false;
 
 
-    public AnsiResponseParser () : base (new StringHeld ()) { }
-
     public string ProcessInput (string input)
     public string ProcessInput (string input)
     {
     {
         var output = new StringBuilder ();
         var output = new StringBuilder ();
@@ -427,9 +429,9 @@ internal class AnsiResponseParser : AnsiResponseParserBase
 
 
     public string Release ()
     public string Release ()
     {
     {
-        lock (lockState)
+        lock (_lockState)
         {
         {
-            string output = heldContent.HeldToString ();
+            string output = _heldContent.HeldToString ();
             ResetState ();
             ResetState ();
 
 
             return output;
             return output;
@@ -437,5 +439,11 @@ internal class AnsiResponseParser : AnsiResponseParserBase
     }
     }
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
-    protected override bool ShouldSwallowUnexpectedResponse () { return UnknownResponseHandler.Invoke (heldContent.HeldToString ()); }
+    protected override bool ShouldSwallowUnexpectedResponse ()
+    {
+        lock (_lockState)
+        {
+            return UnknownResponseHandler.Invoke (_heldContent.HeldToString ());
+        }
+    }
 }
 }

+ 1 - 1
Terminal.Gui/ConsoleDrivers/AnsiResponseParser/IAnsiResponseParser.cs

@@ -30,7 +30,7 @@ public interface IAnsiResponseParser
     ///     that already has one.
     ///     that already has one.
     ///     exists.
     ///     exists.
     /// </exception>
     /// </exception>
-    void ExpectResponse (string terminator, Action<string> response,Action? abandoned, bool persistent);
+    void ExpectResponse (string terminator, Action<string> response, Action? abandoned, bool persistent);
 
 
     /// <summary>
     /// <summary>
     ///     Returns true if there is an existing expectation (i.e. we are waiting a response
     ///     Returns true if there is an existing expectation (i.e. we are waiting a response

+ 21 - 0
Terminal.Gui/ConsoleDrivers/AnsiResponseParser/ReasonCannotSend.cs

@@ -0,0 +1,21 @@
+#nullable enable
+namespace Terminal.Gui;
+
+internal enum ReasonCannotSend
+{
+    /// <summary>
+    ///     No reason given.
+    /// </summary>
+    None = 0,
+
+    /// <summary>
+    ///     The parser is already waiting for a request to complete with the given terminator.
+    /// </summary>
+    OutstandingRequest,
+
+    /// <summary>
+    ///     There have been too many requests sent recently, new requests will be put into
+    ///     queue to prevent console becoming unresponsive.
+    /// </summary>
+    TooManyRequests
+}

+ 5 - 5
Terminal.Gui/ConsoleDrivers/AnsiResponseParser/StringHeld.cs

@@ -6,13 +6,13 @@ namespace Terminal.Gui;
 /// </summary>
 /// </summary>
 internal class StringHeld : IHeld
 internal class StringHeld : IHeld
 {
 {
-    private readonly StringBuilder held = new ();
+    private readonly StringBuilder _held = new ();
 
 
-    public void ClearHeld () { held.Clear (); }
+    public void ClearHeld () { _held.Clear (); }
 
 
-    public string HeldToString () { return held.ToString (); }
+    public string HeldToString () { return _held.ToString (); }
 
 
-    public IEnumerable<object> HeldToObjects () { return held.ToString ().Select (c => (object)c); }
+    public IEnumerable<object> HeldToObjects () { return _held.ToString ().Select (c => (object)c); }
 
 
-    public void AddToHeld (object o) { held.Append ((char)o); }
+    public void AddToHeld (object o) { _held.Append ((char)o); }
 }
 }

+ 4 - 0
Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs

@@ -710,6 +710,10 @@ public abstract class ConsoleDriver : IConsoleDriver
 
 
     internal abstract IAnsiResponseParser GetParser ();
     internal abstract IAnsiResponseParser GetParser ();
 
 
+    /// <summary>
+    ///     Gets the <see cref="AnsiRequestScheduler"/> for this <see cref="ConsoleDriver"/>.
+    /// </summary>
+    /// <returns></returns>
     public AnsiRequestScheduler GetRequestScheduler ()
     public AnsiRequestScheduler GetRequestScheduler ()
     {
     {
         // Lazy initialization because GetParser is virtual
         // Lazy initialization because GetParser is virtual

+ 7 - 0
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -581,6 +581,7 @@ internal class CursesDriver : ConsoleDriver
 
 
     private Curses.Window? _window;
     private Curses.Window? _window;
     private UnixMainLoop? _mainLoopDriver;
     private UnixMainLoop? _mainLoopDriver;
+    // BUGBUG: Fix this nullable issue.
     private object _processInputToken;
     private object _processInputToken;
 
 
     public override MainLoop Init ()
     public override MainLoop Init ()
@@ -730,6 +731,7 @@ internal class CursesDriver : ConsoleDriver
 
 
                 while (wch2 == Curses.KeyMouse)
                 while (wch2 == Curses.KeyMouse)
                 {
                 {
+                    // BUGBUG: Fix this nullable issue.
                     Key kea = null;
                     Key kea = null;
 
 
                     ConsoleKeyInfo [] cki =
                     ConsoleKeyInfo [] cki =
@@ -739,6 +741,7 @@ internal class CursesDriver : ConsoleDriver
                         new ('<', 0, false, false, false)
                         new ('<', 0, false, false, false)
                     };
                     };
                     code = 0;
                     code = 0;
+                    // BUGBUG: Fix this nullable issue.
                     HandleEscSeqResponse (ref code, ref k, ref wch2, ref kea, ref cki);
                     HandleEscSeqResponse (ref code, ref k, ref wch2, ref kea, ref cki);
                 }
                 }
 
 
@@ -796,6 +799,7 @@ internal class CursesDriver : ConsoleDriver
                 k = KeyCode.AltMask | MapCursesKey (wch);
                 k = KeyCode.AltMask | MapCursesKey (wch);
             }
             }
 
 
+            // BUGBUG: Fix this nullable issue.
             Key key = null;
             Key key = null;
 
 
             if (code == 0)
             if (code == 0)
@@ -826,6 +830,7 @@ internal class CursesDriver : ConsoleDriver
                     [
                     [
                         new ((char)KeyCode.Esc, 0, false, false, false), new ((char)wch2, 0, false, false, false)
                         new ((char)KeyCode.Esc, 0, false, false, false), new ((char)wch2, 0, false, false, false)
                     ];
                     ];
+                    // BUGBUG: Fix this nullable issue.
                     HandleEscSeqResponse (ref code, ref k, ref wch2, ref key, ref cki);
                     HandleEscSeqResponse (ref code, ref k, ref wch2, ref key, ref cki);
 
 
                     return;
                     return;
@@ -954,6 +959,7 @@ internal class CursesDriver : ConsoleDriver
 
 
             if (wch2 == 0 || wch2 == 27 || wch2 == Curses.KeyMouse)
             if (wch2 == 0 || wch2 == 27 || wch2 == Curses.KeyMouse)
             {
             {
+                // BUGBUG: Fix this nullable issue.
                 EscSeqUtils.DecodeEscSeq (
                 EscSeqUtils.DecodeEscSeq (
                                           ref consoleKeyInfo,
                                           ref consoleKeyInfo,
                                           ref ck,
                                           ref ck,
@@ -977,6 +983,7 @@ internal class CursesDriver : ConsoleDriver
                         OnMouseEvent (new () { Flags = mf, Position = pos });
                         OnMouseEvent (new () { Flags = mf, Position = pos });
                     }
                     }
 
 
+                    // BUGBUG: Fix this nullable issue.
                     cki = null;
                     cki = null;
 
 
                     if (wch2 == 27)
                     if (wch2 == 27)

+ 1 - 0
Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs

@@ -247,6 +247,7 @@ internal class UnixMainLoop : IMainLoopDriver
 
 
     private class Watch
     private class Watch
     {
     {
+        // BUGBUG: Fix this nullable issue.
         public Func<MainLoop, bool> Callback;
         public Func<MainLoop, bool> Callback;
         public Condition Condition;
         public Condition Condition;
         public int File;
         public int File;

+ 48 - 20
Terminal.Gui/ConsoleDrivers/IConsoleDriver.cs

@@ -31,8 +31,9 @@ public interface IConsoleDriver
     /// <summary>The number of columns visible in the terminal.</summary>
     /// <summary>The number of columns visible in the terminal.</summary>
     int Cols { get; set; }
     int Cols { get; set; }
 
 
+    // BUGBUG: This should not be publicly settable.
     /// <summary>
     /// <summary>
-    ///     The contents of the application output. The driver outputs this buffer to the terminal when
+    ///     Gets or sets the contents of the application output. The driver outputs this buffer to the terminal when
     ///     <see cref="UpdateScreen"/> is called.
     ///     <see cref="UpdateScreen"/> is called.
     ///     <remarks>The format of the array is rows, columns. The first index is the row, the second index is the column.</remarks>
     ///     <remarks>The format of the array is rows, columns. The first index is the row, the second index is the column.</remarks>
     /// </summary>
     /// </summary>
@@ -92,11 +93,13 @@ public interface IConsoleDriver
     /// </returns>
     /// </returns>
     bool IsRuneSupported (Rune rune);
     bool IsRuneSupported (Rune rune);
 
 
+    // BUGBUG: This is not referenced. Can it be removed?
     /// <summary>Tests whether the specified coordinate are valid for drawing.</summary>
     /// <summary>Tests whether the specified coordinate are valid for drawing.</summary>
     /// <param name="col">The column.</param>
     /// <param name="col">The column.</param>
     /// <param name="row">The row.</param>
     /// <param name="row">The row.</param>
     /// <returns>
     /// <returns>
-    ///     <see langword="false"/> if the coordinate is outside the screen bounds or outside of <see cref="ConsoleDriver.Clip"/>.
+    ///     <see langword="false"/> if the coordinate is outside the screen bounds or outside of
+    ///     <see cref="ConsoleDriver.Clip"/>.
     ///     <see langword="true"/> otherwise.
     ///     <see langword="true"/> otherwise.
     /// </returns>
     /// </returns>
     bool IsValidLocation (int col, int row);
     bool IsValidLocation (int col, int row);
@@ -106,19 +109,23 @@ public interface IConsoleDriver
     /// <param name="col">The column.</param>
     /// <param name="col">The column.</param>
     /// <param name="row">The row.</param>
     /// <param name="row">The row.</param>
     /// <returns>
     /// <returns>
-    ///     <see langword="false"/> if the coordinate is outside the screen bounds or outside of <see cref="ConsoleDriver.Clip"/>.
+    ///     <see langword="false"/> if the coordinate is outside the screen bounds or outside of
+    ///     <see cref="ConsoleDriver.Clip"/>.
     ///     <see langword="true"/> otherwise.
     ///     <see langword="true"/> otherwise.
     /// </returns>
     /// </returns>
     bool IsValidLocation (Rune rune, int col, int row);
     bool IsValidLocation (Rune rune, int col, int row);
 
 
     /// <summary>
     /// <summary>
-    ///     Updates <see cref="ConsoleDriver.Col"/> and <see cref="ConsoleDriver.Row"/> to the specified column and row in <see cref="ConsoleDriver.Contents"/>.
-    ///     Used by <see cref="ConsoleDriver.AddRune(System.Text.Rune)"/> and <see cref="ConsoleDriver.AddStr"/> to determine where to add content.
+    ///     Updates <see cref="ConsoleDriver.Col"/> and <see cref="ConsoleDriver.Row"/> to the specified column and row in
+    ///     <see cref="ConsoleDriver.Contents"/>.
+    ///     Used by <see cref="ConsoleDriver.AddRune(System.Text.Rune)"/> and <see cref="ConsoleDriver.AddStr"/> to determine
+    ///     where to add content.
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
     ///     <para>This does not move the cursor on the screen, it only updates the internal state of the driver.</para>
     ///     <para>This does not move the cursor on the screen, it only updates the internal state of the driver.</para>
     ///     <para>
     ///     <para>
-    ///         If <paramref name="col"/> or <paramref name="row"/> are negative or beyond  <see cref="ConsoleDriver.Cols"/> and
+    ///         If <paramref name="col"/> or <paramref name="row"/> are negative or beyond  <see cref="ConsoleDriver.Cols"/>
+    ///         and
     ///         <see cref="ConsoleDriver.Rows"/>, the method still sets those properties.
     ///         <see cref="ConsoleDriver.Rows"/>, the method still sets those properties.
     ///     </para>
     ///     </para>
     /// </remarks>
     /// </remarks>
@@ -130,12 +137,15 @@ public interface IConsoleDriver
     /// <remarks>
     /// <remarks>
     ///     <para>
     ///     <para>
     ///         When the method returns, <see cref="ConsoleDriver.Col"/> will be incremented by the number of columns
     ///         When the method returns, <see cref="ConsoleDriver.Col"/> will be incremented by the number of columns
-    ///         <paramref name="rune"/> required, even if the new column value is outside of the <see cref="ConsoleDriver.Clip"/> or screen
+    ///         <paramref name="rune"/> required, even if the new column value is outside of the
+    ///         <see cref="ConsoleDriver.Clip"/> or screen
     ///         dimensions defined by <see cref="ConsoleDriver.Cols"/>.
     ///         dimensions defined by <see cref="ConsoleDriver.Cols"/>.
     ///     </para>
     ///     </para>
     ///     <para>
     ///     <para>
-    ///         If <paramref name="rune"/> requires more than one column, and <see cref="ConsoleDriver.Col"/> plus the number of columns
-    ///         needed exceeds the <see cref="ConsoleDriver.Clip"/> or screen dimensions, the default Unicode replacement character (U+FFFD)
+    ///         If <paramref name="rune"/> requires more than one column, and <see cref="ConsoleDriver.Col"/> plus the number
+    ///         of columns
+    ///         needed exceeds the <see cref="ConsoleDriver.Clip"/> or screen dimensions, the default Unicode replacement
+    ///         character (U+FFFD)
     ///         will be added instead.
     ///         will be added instead.
     ///     </para>
     ///     </para>
     /// </remarks>
     /// </remarks>
@@ -144,7 +154,8 @@ public interface IConsoleDriver
 
 
     /// <summary>
     /// <summary>
     ///     Adds the specified <see langword="char"/> to the display at the current cursor position. This method is a
     ///     Adds the specified <see langword="char"/> to the display at the current cursor position. This method is a
-    ///     convenience method that calls <see cref="ConsoleDriver.AddRune(System.Text.Rune)"/> with the <see cref="Rune"/> constructor.
+    ///     convenience method that calls <see cref="ConsoleDriver.AddRune(System.Text.Rune)"/> with the <see cref="Rune"/>
+    ///     constructor.
     /// </summary>
     /// </summary>
     /// <param name="c">Character to add.</param>
     /// <param name="c">Character to add.</param>
     void AddRune (char c);
     void AddRune (char c);
@@ -153,7 +164,8 @@ public interface IConsoleDriver
     /// <remarks>
     /// <remarks>
     ///     <para>
     ///     <para>
     ///         When the method returns, <see cref="ConsoleDriver.Col"/> will be incremented by the number of columns
     ///         When the method returns, <see cref="ConsoleDriver.Col"/> will be incremented by the number of columns
-    ///         <paramref name="str"/> required, unless the new column value is outside of the <see cref="ConsoleDriver.Clip"/> or screen
+    ///         <paramref name="str"/> required, unless the new column value is outside of the <see cref="ConsoleDriver.Clip"/>
+    ///         or screen
     ///         dimensions defined by <see cref="ConsoleDriver.Cols"/>.
     ///         dimensions defined by <see cref="ConsoleDriver.Cols"/>.
     ///     </para>
     ///     </para>
     ///     <para>If <paramref name="str"/> requires more columns than are available, the output will be clipped.</para>
     ///     <para>If <paramref name="str"/> requires more columns than are available, the output will be clipped.</para>
@@ -161,9 +173,12 @@ public interface IConsoleDriver
     /// <param name="str">String.</param>
     /// <param name="str">String.</param>
     void AddStr (string str);
     void AddStr (string str);
 
 
-    /// <summary>Fills the specified rectangle with the specified rune, using <see cref="ConsoleDriver.CurrentAttribute"/></summary>
+    /// <summary>
+    ///     Fills the specified rectangle with the specified rune, using <see cref="ConsoleDriver.CurrentAttribute"/>
+    /// </summary>
     /// <remarks>
     /// <remarks>
-    ///     The value of <see cref="ConsoleDriver.Clip"/> is honored. Any parts of the rectangle not in the clip will not be drawn.
+    ///     The value of <see cref="ConsoleDriver.Clip"/> is honored. Any parts of the rectangle not in the clip will not be
+    ///     drawn.
     /// </remarks>
     /// </remarks>
     /// <param name="rect">The Screen-relative rectangle.</param>
     /// <param name="rect">The Screen-relative rectangle.</param>
     /// <param name="rune">The Rune used to fill the rectangle</param>
     /// <param name="rune">The Rune used to fill the rectangle</param>
@@ -185,12 +200,14 @@ public interface IConsoleDriver
     /// </summary>
     /// </summary>
     event EventHandler<EventArgs>? ClearedContents;
     event EventHandler<EventArgs>? ClearedContents;
 
 
+    // BUGBUG: This is not referenced. Can it be removed?
     /// <summary>
     /// <summary>
-    /// Sets <see cref="ConsoleDriver.Contents"/> as dirty for situations where views
-    /// don't need layout and redrawing, but just refresh the screen.
+    ///     Sets <see cref="ConsoleDriver.Contents"/> as dirty for situations where views
+    ///     don't need layout and redrawing, but just refresh the screen.
     /// </summary>
     /// </summary>
     void SetContentsAsDirty ();
     void SetContentsAsDirty ();
 
 
+    // BUGBUG: This is not referenced. Can it be removed?
     /// <summary>Determines if the terminal cursor should be visible or not and sets it accordingly.</summary>
     /// <summary>Determines if the terminal cursor should be visible or not and sets it accordingly.</summary>
     /// <returns><see langword="true"/> upon success</returns>
     /// <returns><see langword="true"/> upon success</returns>
     bool EnsureCursorVisibility ();
     bool EnsureCursorVisibility ();
@@ -224,7 +241,10 @@ public interface IConsoleDriver
     /// <remarks>This is only implemented in <see cref="CursesDriver"/>.</remarks>
     /// <remarks>This is only implemented in <see cref="CursesDriver"/>.</remarks>
     void Suspend ();
     void Suspend ();
 
 
-    /// <summary>Sets the position of the terminal cursor to <see cref="ConsoleDriver.Col"/> and <see cref="ConsoleDriver.Row"/>.</summary>
+    /// <summary>
+    ///     Sets the position of the terminal cursor to <see cref="ConsoleDriver.Col"/> and
+    ///     <see cref="ConsoleDriver.Row"/>.
+    /// </summary>
     void UpdateCursor ();
     void UpdateCursor ();
 
 
     /// <summary>Redraws the physical screen with the contents that have been queued up via any of the printing commands.</summary>
     /// <summary>Redraws the physical screen with the contents that have been queued up via any of the printing commands.</summary>
@@ -263,6 +283,7 @@ public interface IConsoleDriver
     /// <summary>Event fired when a key is pressed down. This is a precursor to <see cref="ConsoleDriver.KeyUp"/>.</summary>
     /// <summary>Event fired when a key is pressed down. This is a precursor to <see cref="ConsoleDriver.KeyUp"/>.</summary>
     event EventHandler<Key>? KeyDown;
     event EventHandler<Key>? KeyDown;
 
 
+    // BUGBUG: This is not referenced. Can it be removed?
     /// <summary>
     /// <summary>
     ///     Called when a key is pressed down. Fires the <see cref="ConsoleDriver.KeyDown"/> event. This is a precursor to
     ///     Called when a key is pressed down. Fires the <see cref="ConsoleDriver.KeyDown"/> event. This is a precursor to
     ///     <see cref="ConsoleDriver.OnKeyUp"/>.
     ///     <see cref="ConsoleDriver.OnKeyUp"/>.
@@ -272,14 +293,17 @@ public interface IConsoleDriver
 
 
     /// <summary>Event fired when a key is released.</summary>
     /// <summary>Event fired when a key is released.</summary>
     /// <remarks>
     /// <remarks>
-    ///     Drivers that do not support key release events will fire this event after <see cref="ConsoleDriver.KeyDown"/> processing is
+    ///     Drivers that do not support key release events will fire this event after <see cref="ConsoleDriver.KeyDown"/>
+    ///     processing is
     ///     complete.
     ///     complete.
     /// </remarks>
     /// </remarks>
     event EventHandler<Key>? KeyUp;
     event EventHandler<Key>? KeyUp;
 
 
+    // BUGBUG: This is not referenced. Can it be removed?
     /// <summary>Called when a key is released. Fires the <see cref="ConsoleDriver.KeyUp"/> event.</summary>
     /// <summary>Called when a key is released. Fires the <see cref="ConsoleDriver.KeyUp"/> event.</summary>
     /// <remarks>
     /// <remarks>
-    ///     Drivers that do not support key release events will call this method after <see cref="ConsoleDriver.OnKeyDown"/> processing
+    ///     Drivers that do not support key release events will call this method after <see cref="ConsoleDriver.OnKeyDown"/>
+    ///     processing
     ///     is complete.
     ///     is complete.
     /// </remarks>
     /// </remarks>
     /// <param name="a"></param>
     /// <param name="a"></param>
@@ -294,15 +318,19 @@ public interface IConsoleDriver
     void SendKeys (char keyChar, ConsoleKey key, bool shift, bool alt, bool ctrl);
     void SendKeys (char keyChar, ConsoleKey key, bool shift, bool alt, bool ctrl);
 
 
     /// <summary>
     /// <summary>
-    /// How long after Esc has been pressed before we give up on getting an Ansi escape sequence
+    ///     How long after Esc has been pressed before we give up on getting an Ansi escape sequence
     /// </summary>
     /// </summary>
     public TimeSpan EscTimeout { get; }
     public TimeSpan EscTimeout { get; }
 
 
     /// <summary>
     /// <summary>
-    /// Queues the given <paramref name="request"/> for execution
+    ///     Queues the given <paramref name="request"/> for execution
     /// </summary>
     /// </summary>
     /// <param name="request"></param>
     /// <param name="request"></param>
     public void QueueAnsiRequest (AnsiEscapeSequenceRequest request);
     public void QueueAnsiRequest (AnsiEscapeSequenceRequest request);
 
 
+    /// <summary>
+    ///     Gets the <see cref="AnsiRequestScheduler"/> for the driver
+    /// </summary>
+    /// <returns></returns>
     public AnsiRequestScheduler GetRequestScheduler ();
     public AnsiRequestScheduler GetRequestScheduler ();
 }
 }

+ 2 - 0
Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs

@@ -223,6 +223,8 @@ internal class NetDriver : ConsoleDriver
         return updated;
         return updated;
     }
     }
     #region Init/End/MainLoop
     #region Init/End/MainLoop
+
+    // BUGBUG: Fix this nullable issue.
     /// <inheritdoc />
     /// <inheritdoc />
     internal override IAnsiResponseParser GetParser () => _mainLoopDriver._netEvents.Parser;
     internal override IAnsiResponseParser GetParser () => _mainLoopDriver._netEvents.Parser;
     internal NetMainLoop? _mainLoopDriver;
     internal NetMainLoop? _mainLoopDriver;

+ 1 - 0
Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs

@@ -41,6 +41,7 @@ internal class WindowsDriver : ConsoleDriver
     private Point _pointMove;
     private Point _pointMove;
     private bool _processButtonClick;
     private bool _processButtonClick;
 
 
+    // BUGBUG: Fix this nullable issue.
     public WindowsDriver ()
     public WindowsDriver ()
     {
     {
         if (Environment.OSVersion.Platform == PlatformID.Win32NT)
         if (Environment.OSVersion.Platform == PlatformID.Win32NT)

+ 0 - 0
Terminal.Gui/Drawing/AnsiColorCode.cs → Terminal.Gui/Drawing/Color/AnsiColorCode.cs


+ 0 - 0
Terminal.Gui/Drawing/Color.ColorExtensions.cs → Terminal.Gui/Drawing/Color/Color.ColorExtensions.cs


+ 0 - 0
Terminal.Gui/Drawing/Color.ColorName.cs → Terminal.Gui/Drawing/Color/Color.ColorName.cs


+ 0 - 0
Terminal.Gui/Drawing/Color.ColorParseException.cs → Terminal.Gui/Drawing/Color/Color.ColorParseException.cs


+ 0 - 0
Terminal.Gui/Drawing/Color.Formatting.cs → Terminal.Gui/Drawing/Color/Color.Formatting.cs


+ 0 - 0
Terminal.Gui/Drawing/Color.Operators.cs → Terminal.Gui/Drawing/Color/Color.Operators.cs


+ 0 - 0
Terminal.Gui/Drawing/Color.cs → Terminal.Gui/Drawing/Color/Color.cs


+ 0 - 0
Terminal.Gui/Drawing/ColorEventArgs.cs → Terminal.Gui/Drawing/Color/ColorEventArgs.cs


+ 0 - 0
Terminal.Gui/Drawing/ColorModel.cs → Terminal.Gui/Drawing/Color/ColorModel.cs


+ 0 - 0
Terminal.Gui/Drawing/Quant/ColorQuantizer.cs → Terminal.Gui/Drawing/Color/ColorQuantizer.cs


+ 0 - 0
Terminal.Gui/Drawing/ColorScheme.Colors.cs → Terminal.Gui/Drawing/Color/ColorScheme.Colors.cs


+ 0 - 0
Terminal.Gui/Drawing/ColorScheme.cs → Terminal.Gui/Drawing/Color/ColorScheme.cs


+ 0 - 0
Terminal.Gui/Drawing/ColorStrings.cs → Terminal.Gui/Drawing/Color/ColorStrings.cs


+ 0 - 0
Terminal.Gui/Drawing/Quant/IColorDistance.cs → Terminal.Gui/Drawing/Color/IColorDistance.cs


+ 0 - 0
Terminal.Gui/Drawing/IColorNameResolver.cs → Terminal.Gui/Drawing/Color/IColorNameResolver.cs


+ 0 - 0
Terminal.Gui/Drawing/ICustomColorFormatter.cs → Terminal.Gui/Drawing/Color/ICustomColorFormatter.cs


+ 0 - 0
Terminal.Gui/Drawing/W3CColors.cs → Terminal.Gui/Drawing/Color/W3CColors.cs


+ 0 - 0
Terminal.Gui/Drawing/IntersectionDefinition.cs → Terminal.Gui/Drawing/LineCanvas/IntersectionDefinition.cs


+ 0 - 0
Terminal.Gui/Drawing/IntersectionRuneType.cs → Terminal.Gui/Drawing/LineCanvas/IntersectionRuneType.cs


+ 0 - 0
Terminal.Gui/Drawing/IntersectionType.cs → Terminal.Gui/Drawing/LineCanvas/IntersectionType.cs


+ 0 - 0
Terminal.Gui/Drawing/LineCanvas.cs → Terminal.Gui/Drawing/LineCanvas/LineCanvas.cs


+ 0 - 0
Terminal.Gui/Drawing/LineStyle.cs → Terminal.Gui/Drawing/LineCanvas/LineStyle.cs


+ 0 - 0
Terminal.Gui/Drawing/StraightLine.cs → Terminal.Gui/Drawing/LineCanvas/StraightLine.cs


+ 0 - 0
Terminal.Gui/Drawing/StraightLineExtensions.cs → Terminal.Gui/Drawing/LineCanvas/StraightLineExtensions.cs


+ 4 - 4
Terminal.Gui/Drawing/SixelEncoder.cs → Terminal.Gui/Drawing/Sixel/SixelEncoder.cs

@@ -47,11 +47,11 @@ public class SixelEncoder
     /// <returns></returns>
     /// <returns></returns>
     public string EncodeSixel (Color [,] pixels)
     public string EncodeSixel (Color [,] pixels)
     {
     {
-        const string start = "\u001bP"; // Start sixel sequence
+        const string START = "\u001bP"; // Start sixel sequence
 
 
         string defaultRatios = AnyHasAlphaOfZero (pixels) ? "0;1;0" : "0;0;0"; // Defaults for aspect ratio and grid size
         string defaultRatios = AnyHasAlphaOfZero (pixels) ? "0;1;0" : "0;0;0"; // Defaults for aspect ratio and grid size
-        const string completeStartSequence = "q"; // Signals beginning of sixel image data
-        const string noScaling = "\"1;1;"; // no scaling factors (1x1);
+        const string COMPLETE_START_SEQUENCE = "q"; // Signals beginning of sixel image data
+        const string NO_SCALING = "\"1;1;"; // no scaling factors (1x1);
 
 
         string fillArea = GetFillArea (pixels);
         string fillArea = GetFillArea (pixels);
 
 
@@ -61,7 +61,7 @@ public class SixelEncoder
 
 
         const string terminator = "\u001b\\"; // End sixel sequence
         const string terminator = "\u001b\\"; // End sixel sequence
 
 
-        return start + defaultRatios + completeStartSequence + noScaling + fillArea + pallette + pixelData + terminator;
+        return START + defaultRatios + COMPLETE_START_SEQUENCE + NO_SCALING + fillArea + pallette + pixelData + terminator;
     }
     }
 
 
     private string WriteSixel (Color [,] pixels)
     private string WriteSixel (Color [,] pixels)

+ 61 - 57
Terminal.Gui/Drawing/SixelSupportDetector.cs → Terminal.Gui/Drawing/Sixel/SixelSupportDetector.cs

@@ -9,12 +9,14 @@ namespace Terminal.Gui;
 public class SixelSupportDetector
 public class SixelSupportDetector
 {
 {
     /// <summary>
     /// <summary>
-    /// Sends Ansi escape sequences to the console to determine whether
-    /// sixel is supported (and <see cref="SixelSupportResult.Resolution"/>
-    /// etc).
+    ///     Sends Ansi escape sequences to the console to determine whether
+    ///     sixel is supported (and <see cref="SixelSupportResult.Resolution"/>
+    ///     etc).
     /// </summary>
     /// </summary>
-    /// <returns>Description of sixel support, may include assumptions where
-    /// expected response codes are not returned by console.</returns>
+    /// <returns>
+    ///     Description of sixel support, may include assumptions where
+    ///     expected response codes are not returned by console.
+    /// </returns>
     public void Detect (Action<SixelSupportResult> resultCallback)
     public void Detect (Action<SixelSupportResult> resultCallback)
     {
     {
         var result = new SixelSupportResult ();
         var result = new SixelSupportResult ();
@@ -22,75 +24,76 @@ public class SixelSupportDetector
         IsSixelSupportedByDar (result, resultCallback);
         IsSixelSupportedByDar (result, resultCallback);
     }
     }
 
 
-
     private void TryGetResolutionDirectly (SixelSupportResult result, Action<SixelSupportResult> resultCallback)
     private void TryGetResolutionDirectly (SixelSupportResult result, Action<SixelSupportResult> resultCallback)
     {
     {
         // Expect something like:
         // Expect something like:
         //<esc>[6;20;10t
         //<esc>[6;20;10t
-        QueueRequest (EscSeqUtils.CSI_RequestSixelResolution,
-                      (r) =>
+        QueueRequest (
+                      EscSeqUtils.CSI_RequestSixelResolution,
+                      r =>
                       {
                       {
                           // Terminal supports directly responding with resolution
                           // Terminal supports directly responding with resolution
-                          var match = Regex.Match (r, @"\[\d+;(\d+);(\d+)t$");
+                          Match match = Regex.Match (r, @"\[\d+;(\d+);(\d+)t$");
 
 
                           if (match.Success)
                           if (match.Success)
                           {
                           {
-                              if (int.TryParse (match.Groups [1].Value, out var ry) &&
-                                  int.TryParse (match.Groups [2].Value, out var rx))
+                              if (int.TryParse (match.Groups [1].Value, out int ry) && int.TryParse (match.Groups [2].Value, out int rx))
                               {
                               {
-                                  result.Resolution = new Size (rx, ry);
+                                  result.Resolution = new (rx, ry);
                               }
                               }
                           }
                           }
 
 
                           // Finished
                           // Finished
                           resultCallback.Invoke (result);
                           resultCallback.Invoke (result);
-
                       },
                       },
+
                       // Request failed, so try to compute instead
                       // Request failed, so try to compute instead
-                      ()=>TryComputeResolution (result,resultCallback));
+                      () => TryComputeResolution (result, resultCallback));
     }
     }
 
 
-
     private void TryComputeResolution (SixelSupportResult result, Action<SixelSupportResult> resultCallback)
     private void TryComputeResolution (SixelSupportResult result, Action<SixelSupportResult> resultCallback)
     {
     {
         string windowSize;
         string windowSize;
         string sizeInChars;
         string sizeInChars;
 
 
-        QueueRequest (EscSeqUtils.CSI_RequestWindowSizeInPixels,
-                      (r1)=>
+        QueueRequest (
+                      EscSeqUtils.CSI_RequestWindowSizeInPixels,
+                      r1 =>
                       {
                       {
                           windowSize = r1;
                           windowSize = r1;
 
 
-                          QueueRequest (EscSeqUtils.CSI_ReportTerminalSizeInChars,
-                                        (r2) =>
+                          QueueRequest (
+                                        EscSeqUtils.CSI_ReportTerminalSizeInChars,
+                                        r2 =>
                                         {
                                         {
                                             sizeInChars = r2;
                                             sizeInChars = r2;
-                                            ComputeResolution (result,windowSize,sizeInChars);
+                                            ComputeResolution (result, windowSize, sizeInChars);
                                             resultCallback (result);
                                             resultCallback (result);
-
-                                        }, abandoned: () => resultCallback (result));
-                      },abandoned: ()=>resultCallback(result));
+                                        },
+                                        () => resultCallback (result));
+                      },
+                      () => resultCallback (result));
     }
     }
 
 
     private void ComputeResolution (SixelSupportResult result, string windowSize, string sizeInChars)
     private void ComputeResolution (SixelSupportResult result, string windowSize, string sizeInChars)
     {
     {
         // Fallback to window size in pixels and characters
         // Fallback to window size in pixels and characters
         // Example [4;600;1200t
         // Example [4;600;1200t
-        var pixelMatch = Regex.Match (windowSize, @"\[\d+;(\d+);(\d+)t$");
+        Match pixelMatch = Regex.Match (windowSize, @"\[\d+;(\d+);(\d+)t$");
 
 
         // Example [8;30;120t
         // Example [8;30;120t
-        var charMatch = Regex.Match (sizeInChars, @"\[\d+;(\d+);(\d+)t$");
+        Match charMatch = Regex.Match (sizeInChars, @"\[\d+;(\d+);(\d+)t$");
 
 
         if (pixelMatch.Success && charMatch.Success)
         if (pixelMatch.Success && charMatch.Success)
         {
         {
             // Extract pixel dimensions
             // Extract pixel dimensions
-            if (int.TryParse (pixelMatch.Groups [1].Value, out var pixelHeight)
-                && int.TryParse (pixelMatch.Groups [2].Value, out var pixelWidth)
+            if (int.TryParse (pixelMatch.Groups [1].Value, out int pixelHeight)
+                && int.TryParse (pixelMatch.Groups [2].Value, out int pixelWidth)
                 &&
                 &&
 
 
                 // Extract character dimensions
                 // Extract character dimensions
-                int.TryParse (charMatch.Groups [1].Value, out var charHeight)
-                && int.TryParse (charMatch.Groups [2].Value, out var charWidth)
+                int.TryParse (charMatch.Groups [1].Value, out int charHeight)
+                && int.TryParse (charMatch.Groups [2].Value, out int charWidth)
                 && charWidth != 0
                 && charWidth != 0
                 && charHeight != 0) // Avoid divide by zero
                 && charHeight != 0) // Avoid divide by zero
             {
             {
@@ -99,31 +102,32 @@ public class SixelSupportDetector
                 var cellHeight = (int)Math.Round ((double)pixelHeight / charHeight);
                 var cellHeight = (int)Math.Round ((double)pixelHeight / charHeight);
 
 
                 // Set the resolution based on the character cell size
                 // Set the resolution based on the character cell size
-                result.Resolution = new Size (cellWidth, cellHeight);
+                result.Resolution = new (cellWidth, cellHeight);
             }
             }
         }
         }
     }
     }
 
 
-    private void IsSixelSupportedByDar (SixelSupportResult result,Action<SixelSupportResult> resultCallback)
+    private void IsSixelSupportedByDar (SixelSupportResult result, Action<SixelSupportResult> resultCallback)
     {
     {
         QueueRequest (
         QueueRequest (
-              EscSeqUtils.CSI_SendDeviceAttributes,
-              (r) =>
-              {
-                  result.IsSupported = ResponseIndicatesSupport (r);
-
-                  if (result.IsSupported)
-                  {
-                      TryGetResolutionDirectly (result, resultCallback);
-                  }
-                  else
-                  {
-                      resultCallback (result);
-                  }
-              },abandoned: () => resultCallback(result));
+                      EscSeqUtils.CSI_SendDeviceAttributes,
+                      r =>
+                      {
+                          result.IsSupported = ResponseIndicatesSupport (r);
+
+                          if (result.IsSupported)
+                          {
+                              TryGetResolutionDirectly (result, resultCallback);
+                          }
+                          else
+                          {
+                              resultCallback (result);
+                          }
+                      },
+                      () => resultCallback (result));
     }
     }
 
 
-    private void QueueRequest (AnsiEscapeSequenceRequest req, Action<string> responseCallback, Action abandoned)
+    private static void QueueRequest (AnsiEscapeSequenceRequest req, Action<string> responseCallback, Action abandoned)
     {
     {
         var newRequest = new AnsiEscapeSequenceRequest
         var newRequest = new AnsiEscapeSequenceRequest
         {
         {
@@ -133,29 +137,29 @@ public class SixelSupportDetector
             Abandoned = abandoned
             Abandoned = abandoned
         };
         };
 
 
-        Application.Driver.QueueAnsiRequest (newRequest);
+        Application.Driver?.QueueAnsiRequest (newRequest);
     }
     }
 
 
-    private bool ResponseIndicatesSupport (string response)
-    {
-        return response.Split (';').Contains ("4");
-    }
+    private static bool ResponseIndicatesSupport (string response) { return response.Split (';').Contains ("4"); }
 
 
-    private bool IsWindowsTerminal ()
+    private static bool IsWindowsTerminal ()
     {
     {
-        return  !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable ("WT_SESSION"));;
+        return !string.IsNullOrWhiteSpace (Environment.GetEnvironmentVariable ("WT_SESSION"));
+
+        ;
     }
     }
-    private bool IsXtermWithTransparency ()
+
+    private static bool IsXtermWithTransparency ()
     {
     {
         // Check if running in real xterm (XTERM_VERSION is more reliable than TERM)
         // Check if running in real xterm (XTERM_VERSION is more reliable than TERM)
-        var xtermVersionStr = Environment.GetEnvironmentVariable ("XTERM_VERSION");
+        string xtermVersionStr = Environment.GetEnvironmentVariable ("XTERM_VERSION");
 
 
         // If XTERM_VERSION exists, we are in a real xterm
         // If XTERM_VERSION exists, we are in a real xterm
-        if (!string.IsNullOrWhiteSpace (xtermVersionStr) && int.TryParse (xtermVersionStr, out var xtermVersion) && xtermVersion >= 370)
+        if (!string.IsNullOrWhiteSpace (xtermVersionStr) && int.TryParse (xtermVersionStr, out int xtermVersion) && xtermVersion >= 370)
         {
         {
             return true;
             return true;
         }
         }
 
 
         return false;
         return false;
     }
     }
-}
+}

+ 1 - 1
Terminal.Gui/Drawing/SixelSupportResult.cs → Terminal.Gui/Drawing/Sixel/SixelSupportResult.cs

@@ -2,7 +2,7 @@
 
 
 /// <summary>
 /// <summary>
 ///     Describes the discovered state of sixel support and ancillary information
 ///     Describes the discovered state of sixel support and ancillary information
-///     e.g. <see cref="Resolution"/>. You can use any <see cref="ISixelSupportDetector"/>
+///     e.g. <see cref="Resolution"/>. You can use any <see cref="SixelSupportDetector"/>
 ///     to discover this information.
 ///     to discover this information.
 /// </summary>
 /// </summary>
 public class SixelSupportResult
 public class SixelSupportResult

+ 0 - 0
Terminal.Gui/Drawing/SixelToRender.cs → Terminal.Gui/Drawing/Sixel/SixelToRender.cs


+ 14 - 16
UICatalog/Scenarios/AnsiRequestsScenario.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
 using Terminal.Gui;
 using Terminal.Gui;
-using static System.Runtime.InteropServices.JavaScript.JSType;
 
 
 namespace UICatalog.Scenarios;
 namespace UICatalog.Scenarios;
 
 
@@ -13,14 +12,13 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
 {
 {
     private GraphView _graphView;
     private GraphView _graphView;
 
 
-    private DateTime start = DateTime.Now;
     private ScatterSeries _sentSeries;
     private ScatterSeries _sentSeries;
     private ScatterSeries _answeredSeries;
     private ScatterSeries _answeredSeries;
 
 
-    private List<DateTime> sends = new ();
+    private readonly List<DateTime> _sends = new ();
 
 
-    private object lockAnswers = new object ();
-    private Dictionary<DateTime, string> answers = new ();
+    private readonly object _lockAnswers = new object ();
+    private readonly Dictionary<DateTime, string> _answers = new ();
     private Label _lblSummary;
     private Label _lblSummary;
 
 
     public override void Main ()
     public override void Main ()
@@ -82,7 +80,7 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
             "CSI_RequestCursorPositionReport",
             "CSI_RequestCursorPositionReport",
             "CSI_SendDeviceAttributes2"
             "CSI_SendDeviceAttributes2"
         };
         };
-
+        // TODO: This UI would be cleaner/less rigid if Pos.Align were used
         var cbRequests = new ComboBox () { Width = 40, Height = 5, ReadOnly = true, Source = new ListWrapper<string> (new (scrRequests)) };
         var cbRequests = new ComboBox () { Width = 40, Height = 5, ReadOnly = true, Source = new ListWrapper<string> (new (scrRequests)) };
         w.Add (cbRequests);
         w.Add (cbRequests);
 
 
@@ -225,7 +223,7 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
                                 TimeSpan.FromMilliseconds (1000),
                                 TimeSpan.FromMilliseconds (1000),
                                 () =>
                                 () =>
                                 {
                                 {
-                                    lock (lockAnswers)
+                                    lock (_lockAnswers)
                                     {
                                     {
                                         UpdateGraph ();
                                         UpdateGraph ();
 
 
@@ -327,15 +325,15 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
 
 
     private string GetSummary ()
     private string GetSummary ()
     {
     {
-        if (answers.Count == 0)
+        if (_answers.Count == 0)
         {
         {
             return "No requests sent yet";
             return "No requests sent yet";
         }
         }
 
 
-        var last = answers.Last ().Value;
+        var last = _answers.Last ().Value;
 
 
-        var unique = answers.Values.Distinct ().Count ();
-        var total = answers.Count;
+        var unique = _answers.Values.Distinct ().Count ();
+        var total = _answers.Count;
 
 
         return $"Last:{last} U:{unique} T:{total}";
         return $"Last:{last} U:{unique} T:{total}";
     }
     }
@@ -361,12 +359,12 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
 
 
     private void UpdateGraph ()
     private void UpdateGraph ()
     {
     {
-        _sentSeries.Points = sends
+        _sentSeries.Points = _sends
                              .GroupBy (ToSeconds)
                              .GroupBy (ToSeconds)
                              .Select (g => new PointF (g.Key, g.Count ()))
                              .Select (g => new PointF (g.Key, g.Count ()))
                              .ToList ();
                              .ToList ();
 
 
-        _answeredSeries.Points = answers.Keys
+        _answeredSeries.Points = _answers.Keys
                                         .GroupBy (ToSeconds)
                                         .GroupBy (ToSeconds)
                                         .Select (g => new PointF (g.Key, g.Count ()))
                                         .Select (g => new PointF (g.Key, g.Count ()))
                                         .ToList ();
                                         .ToList ();
@@ -389,14 +387,14 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
                                                  Terminator = EscSeqUtils.CSI_SendDeviceAttributes.Terminator,
                                                  Terminator = EscSeqUtils.CSI_SendDeviceAttributes.Terminator,
                                                  ResponseReceived = HandleResponse
                                                  ResponseReceived = HandleResponse
                                              });
                                              });
-        sends.Add (DateTime.Now);
+        _sends.Add (DateTime.Now);
     }
     }
 
 
     private void HandleResponse (string response)
     private void HandleResponse (string response)
     {
     {
-        lock (lockAnswers)
+        lock (_lockAnswers)
         {
         {
-            answers.Add (DateTime.Now, response);
+            _answers.Add (DateTime.Now, response);
         }
         }
     }
     }
 }
 }

+ 11 - 14
UICatalog/Scenarios/Images.cs

@@ -62,7 +62,7 @@ public class Images : Scenario
     private SixelToRender _sixelImage;
     private SixelToRender _sixelImage;
 
 
     // Start by assuming no support
     // Start by assuming no support
-    private SixelSupportResult _sixelSupportResult = new SixelSupportResult ();
+    private SixelSupportResult _sixelSupportResult = new ();
     private CheckBox _cbSupportsSixel;
     private CheckBox _cbSupportsSixel;
 
 
     public override void Main ()
     public override void Main ()
@@ -95,8 +95,8 @@ public class Images : Scenario
             Text = "supports true color "
             Text = "supports true color "
         };
         };
         _win.Add (cbSupportsTrueColor);
         _win.Add (cbSupportsTrueColor);
-        
-        _cbSupportsSixel = new CheckBox
+
+        _cbSupportsSixel = new()
         {
         {
             X = Pos.Right (lblDriverName) + 2,
             X = Pos.Right (lblDriverName) + 2,
             Y = 1,
             Y = 1,
@@ -104,26 +104,24 @@ public class Images : Scenario
             Text = "Supports Sixel"
             Text = "Supports Sixel"
         };
         };
 
 
-        var lblSupportsSixel = new Label ()
+        var lblSupportsSixel = new Label
         {
         {
-
             X = Pos.Right (lblDriverName) + 2,
             X = Pos.Right (lblDriverName) + 2,
             Y = Pos.Bottom (_cbSupportsSixel),
             Y = Pos.Bottom (_cbSupportsSixel),
             Text = "(Check if your terminal supports Sixel)"
             Text = "(Check if your terminal supports Sixel)"
         };
         };
 
 
-
         /*        CheckedState = _sixelSupportResult.IsSupported
         /*        CheckedState = _sixelSupportResult.IsSupported
                                    ? CheckState.Checked
                                    ? CheckState.Checked
                                    : CheckState.UnChecked;*/
                                    : CheckState.UnChecked;*/
 
 
         _cbSupportsSixel.CheckedStateChanging += (s, e) =>
         _cbSupportsSixel.CheckedStateChanging += (s, e) =>
-                                                {
-                                                    _sixelSupportResult.IsSupported = e.NewValue == CheckState.Checked;
-                                                    SetupSixelSupported (e.NewValue == CheckState.Checked);
-                                                    ApplyShowTabViewHack ();
-                                                };
-                                                
+                                                 {
+                                                     _sixelSupportResult.IsSupported = e.NewValue == CheckState.Checked;
+                                                     SetupSixelSupported (e.NewValue == CheckState.Checked);
+                                                     ApplyShowTabViewHack ();
+                                                 };
+
         _win.Add (_cbSupportsSixel);
         _win.Add (_cbSupportsSixel);
 
 
         var cbUseTrueColor = new CheckBox
         var cbUseTrueColor = new CheckBox
@@ -174,7 +172,6 @@ public class Images : Scenario
         _cbSupportsSixel.CheckedState = newResult.IsSupported ? CheckState.Checked : CheckState.UnChecked;
         _cbSupportsSixel.CheckedState = newResult.IsSupported ? CheckState.Checked : CheckState.UnChecked;
         _pxX.Value = _sixelSupportResult.Resolution.Width;
         _pxX.Value = _sixelSupportResult.Resolution.Width;
         _pxY.Value = _sixelSupportResult.Resolution.Height;
         _pxY.Value = _sixelSupportResult.Resolution.Height;
-
     }
     }
 
 
     private void SetupSixelSupported (bool isSupported)
     private void SetupSixelSupported (bool isSupported)
@@ -311,7 +308,7 @@ public class Images : Scenario
     {
     {
         // TODO HACK: This hack seems to be required to make tabview actually refresh itself
         // TODO HACK: This hack seems to be required to make tabview actually refresh itself
         _tabView.SetNeedsDraw ();
         _tabView.SetNeedsDraw ();
-        var orig = _tabView.SelectedTab;
+        Tab orig = _tabView.SelectedTab;
         _tabView.SelectedTab = _tabView.Tabs.Except (new [] { orig }).ElementAt (0);
         _tabView.SelectedTab = _tabView.Tabs.Except (new [] { orig }).ElementAt (0);
         _tabView.SelectedTab = orig;
         _tabView.SelectedTab = orig;
     }
     }

+ 0 - 2
UnitTests/ConsoleDrivers/AnsiResponseParserTests.cs

@@ -416,8 +416,6 @@ public class AnsiResponseParserTests (ITestOutputHelper output)
     [Fact]
     [Fact]
     public void ShouldSwallowUnknownResponses_WhenDelegateSaysSo ()
     public void ShouldSwallowUnknownResponses_WhenDelegateSaysSo ()
     {
     {
-        int i = 0;
-
         // Swallow all unknown escape codes
         // Swallow all unknown escape codes
         _parser1.UnexpectedResponseHandler = _ => true;
         _parser1.UnexpectedResponseHandler = _ => true;
         _parser2.UnknownResponseHandler = _ => true;
         _parser2.UnknownResponseHandler = _ => true;