diff --git a/Terminal.Gui/ConsoleDrivers/AnsiEscapeSequenceRequest.cs b/Terminal.Gui/ConsoleDrivers/AnsiEscapeSequenceRequest.cs
index d57d99796..af6e7b924 100644
--- a/Terminal.Gui/ConsoleDrivers/AnsiEscapeSequenceRequest.cs
+++ b/Terminal.Gui/ConsoleDrivers/AnsiEscapeSequenceRequest.cs
@@ -43,12 +43,9 @@ public class AnsiEscapeSequenceRequest
public required string Terminator { get; init; }
///
- /// Sends the to the raw output stream of the current .
- /// Only call this method from the main UI thread. You should use if
- /// sending many requests.
+ /// Sends the to the raw output stream of the current .
+ /// Only call this method from the main UI thread. You should use if
+ /// sending many requests.
///
- public void Send ()
- {
- Application.Driver?.RawWrite (Request);
- }
+ public void Send () { Application.Driver?.RawWrite (Request); }
}
diff --git a/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiRequestScheduler.cs b/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiRequestScheduler.cs
index 1a6cfab1f..b5c6d4780 100644
--- a/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiRequestScheduler.cs
+++ b/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiRequestScheduler.cs
@@ -4,10 +4,10 @@ using System.Collections.Concurrent;
namespace Terminal.Gui;
///
-/// Manages made to an .
-/// Ensures there are not 2+ outstanding requests with the same terminator, throttles request sends
-/// to prevent console becoming unresponsive and handles evicting ignored requests (no reply from
-/// terminal).
+/// Manages made to an .
+/// Ensures there are not 2+ outstanding requests with the same terminator, throttles request sends
+/// to prevent console becoming unresponsive and handles evicting ignored requests (no reply from
+/// terminal).
///
internal class AnsiRequestScheduler
{
@@ -17,53 +17,55 @@ internal class AnsiRequestScheduler
private readonly List> _requests = new ();
///
- ///
- /// Dictionary where key is ansi request terminator and value is when we last sent a request for
- /// this terminator. Combined with this prevents hammering the console
- /// with too many requests in sequence which can cause console to freeze as there is no space for
- /// regular screen drawing / mouse events etc to come in.
- ///
- ///
- /// When user exceeds the throttle, new requests accumulate in (i.e. remain
- /// queued).
- ///
+ ///
+ /// Dictionary where key is ansi request terminator and value is when we last sent a request for
+ /// this terminator. Combined with this prevents hammering the console
+ /// with too many requests in sequence which can cause console to freeze as there is no space for
+ /// regular screen drawing / mouse events etc to come in.
+ ///
+ ///
+ /// When user exceeds the throttle, new requests accumulate in (i.e. remain
+ /// queued).
+ ///
///
private readonly ConcurrentDictionary _lastSend = new ();
///
- /// Number of milliseconds after sending a request that we allow
- /// another request to go out.
+ /// Number of milliseconds after sending a request that we allow
+ /// another request to go out.
///
- private TimeSpan _throttle = TimeSpan.FromMilliseconds (100);
- private TimeSpan _runScheduleThrottle = TimeSpan.FromMilliseconds (100);
+ private readonly TimeSpan _throttle = TimeSpan.FromMilliseconds (100);
+
+ private readonly TimeSpan _runScheduleThrottle = TimeSpan.FromMilliseconds (100);
///
- /// If console has not responded to a request after this period of time, we assume that it is never going
- /// to respond. Only affects when we try to send a new request with the same terminator - at which point
- /// we tell the parser to stop expecting the old request and start expecting the new request.
+ /// If console has not responded to a request after this period of time, we assume that it is never going
+ /// to respond. Only affects when we try to send a new request with the same terminator - at which point
+ /// we tell the parser to stop expecting the old request and start expecting the new request.
///
- private TimeSpan _staleTimeout = TimeSpan.FromSeconds (5);
+ private readonly TimeSpan _staleTimeout = TimeSpan.FromSeconds (5);
+ private readonly DateTime _lastRun;
- private DateTime _lastRun;
public AnsiRequestScheduler (IAnsiResponseParser parser, Func? now = null)
{
_parser = parser;
_now = now ?? (() => DateTime.Now);
_lastRun = _now ();
}
+
///
- /// Sends the immediately or queues it if there is already
- /// an outstanding request for the given .
+ /// Sends the immediately or queues it if there is already
+ /// an outstanding request for the given .
///
///
/// if request was sent immediately. if it was queued.
public bool SendOrSchedule (AnsiEscapeSequenceRequest request)
{
-
- if (CanSend (request, out var reason))
+ if (CanSend (request, out ReasonCannotSend reason))
{
Send (request);
+
return true;
}
@@ -75,26 +77,28 @@ internal class AnsiRequestScheduler
if (CanSend (request, out _))
{
Send (request);
+
return true;
}
}
- _requests.Add (Tuple.Create (request, _now()));
+ _requests.Add (Tuple.Create (request, _now ()));
+
return false;
}
///
- /// Looks to see if the last time we sent
- /// is a long time ago. If so we assume that we will never get a response and
- /// can proceed with a new request for this terminator (returning ).
+ /// Looks to see if the last time we sent
+ /// is a long time ago. If so we assume that we will never get a response and
+ /// can proceed with a new request for this terminator (returning ).
///
///
///
private bool EvictStaleRequests (string withTerminator)
{
- if (_lastSend.TryGetValue (withTerminator, out var dt))
+ if (_lastSend.TryGetValue (withTerminator, out DateTime dt))
{
- if (_now() - dt > _staleTimeout)
+ if (_now () - dt > _staleTimeout)
{
_parser.StopExpecting (withTerminator, false);
@@ -105,23 +109,26 @@ internal class AnsiRequestScheduler
return false;
}
-
///
- /// Identifies and runs any that can be sent based on the
- /// current outstanding requests of the parser.
+ /// Identifies and runs any that can be sent based on the
+ /// current outstanding requests of the parser.
///
- /// Repeated requests to run the schedule over short period of time will be ignored.
- /// Pass to override this behaviour and force evaluation of outstanding requests.
- /// if a request was found and run.
- /// if no outstanding requests or all have existing outstanding requests underway in parser.
+ ///
+ /// Repeated requests to run the schedule over short period of time will be ignored.
+ /// Pass to override this behaviour and force evaluation of outstanding requests.
+ ///
+ ///
+ /// if a request was found and run.
+ /// if no outstanding requests or all have existing outstanding requests underway in parser.
+ ///
public bool RunSchedule (bool force = false)
{
- if (!force && _now() - _lastRun < _runScheduleThrottle)
+ if (!force && _now () - _lastRun < _runScheduleThrottle)
{
return false;
}
- var opportunity = _requests.FirstOrDefault (r => CanSend (r.Item1, out _));
+ Tuple? opportunity = _requests.FirstOrDefault (r => CanSend (r.Item1, out _));
if (opportunity != null)
{
@@ -136,7 +143,7 @@ internal class AnsiRequestScheduler
private void Send (AnsiEscapeSequenceRequest r)
{
- _lastSend.AddOrUpdate (r.Terminator, _=>_now(), (_, _) => _now());
+ _lastSend.AddOrUpdate (r.Terminator, _ => _now (), (_, _) => _now ());
_parser.ExpectResponse (r.Terminator, r.ResponseReceived, false);
r.Send ();
}
@@ -146,16 +153,19 @@ internal class AnsiRequestScheduler
if (ShouldThrottle (r))
{
reason = ReasonCannotSend.TooManyRequests;
+
return false;
}
if (_parser.IsExpecting (r.Terminator))
{
reason = ReasonCannotSend.OutstandingRequest;
+
return false;
}
- reason = default;
+ reason = default (ReasonCannotSend);
+
return true;
}
@@ -163,7 +173,7 @@ internal class AnsiRequestScheduler
{
if (_lastSend.TryGetValue (r.Terminator, out DateTime value))
{
- return _now() - value < _throttle;
+ return _now () - value < _throttle;
}
return false;
@@ -173,18 +183,18 @@ internal class AnsiRequestScheduler
internal enum ReasonCannotSend
{
///
- /// No reason given.
+ /// No reason given.
///
None = 0,
///
- /// The parser is already waiting for a request to complete with the given terminator.
+ /// The parser is already waiting for a request to complete with the given terminator.
///
OutstandingRequest,
///
- /// There have been too many requests sent recently, new requests will be put into
- /// queue to prevent console becoming unresponsive.
+ /// There have been too many requests sent recently, new requests will be put into
+ /// queue to prevent console becoming unresponsive.
///
TooManyRequests
}
diff --git a/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiResponseExpectation.cs b/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiResponseExpectation.cs
index 75fdb308a..e4c22d758 100644
--- a/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiResponseExpectation.cs
+++ b/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiResponseExpectation.cs
@@ -3,8 +3,5 @@ namespace Terminal.Gui;
internal record AnsiResponseExpectation (string Terminator, Action Response)
{
- public bool Matches (string cur)
- {
- return cur.EndsWith (Terminator);
- }
-}
\ No newline at end of file
+ public bool Matches (string cur) { return cur.EndsWith (Terminator); }
+}
diff --git a/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiResponseParser.cs b/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiResponseParser.cs
index 71f67d6f8..71e489b9e 100644
--- a/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiResponseParser.cs
+++ b/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiResponseParser.cs
@@ -2,25 +2,25 @@
namespace Terminal.Gui;
-
internal abstract class AnsiResponseParserBase : IAnsiResponseParser
{
- protected object lockExpectedResponses = new object();
+ protected object lockExpectedResponses = new ();
+
+ protected object lockState = new ();
- protected object lockState = new object ();
///
- /// Responses we are expecting to come in.
+ /// Responses we are expecting to come in.
///
protected readonly List expectedResponses = new ();
///
- /// Collection of responses that we .
+ /// Collection of responses that we .
///
protected readonly List lateResponses = new ();
///
- /// Responses that you want to look out for that will come in continuously e.g. mouse events.
- /// Key is the terminator.
+ /// Responses that you want to look out for that will come in continuously e.g. mouse events.
+ /// Key is the terminator.
///
protected readonly List persistentExpectations = new ();
@@ -47,21 +47,20 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
// These all are valid terminators on ansi responses,
// 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
- protected readonly HashSet _knownTerminators = new (new []
- {
- '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- // No - N or O
- 'P', 'Q', 'R', 'S', 'T', 'W', 'X', 'Z',
- '^', '`', '~',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
- 'l', 'm', 'n',
- 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
- });
+ protected readonly HashSet _knownTerminators = new (
+ new []
+ {
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- protected AnsiResponseParserBase (IHeld heldContent)
- {
- this.heldContent = heldContent;
- }
+ // No - N or O
+ 'P', 'Q', 'R', 'S', 'T', 'W', 'X', 'Z',
+ '^', '`', '~',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+ 'l', 'm', 'n',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
+ });
+
+ protected AnsiResponseParserBase (IHeld heldContent) { this.heldContent = heldContent; }
protected void ResetState ()
{
@@ -187,8 +186,8 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
if (MatchResponse (
cur,
expectedResponses,
- invokeCallback: true,
- removeExpectation: true))
+ true,
+ true))
{
return false;
}
@@ -197,8 +196,8 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
if (MatchResponse (
cur,
lateResponses,
- invokeCallback: false,
- removeExpectation: true))
+ false,
+ true))
{
return false;
}
@@ -207,8 +206,8 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
if (MatchResponse (
cur,
persistentExpectations,
- invokeCallback: true,
- removeExpectation: false))
+ true,
+ false))
{
return false;
}
@@ -222,11 +221,12 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
State = AnsiResponseParserState.Normal;
// Maybe swallow anyway if user has custom delegate
- var swallow = ShouldSwallowUnexpectedResponse ();
+ bool swallow = ShouldSwallowUnexpectedResponse ();
if (swallow)
{
heldContent.ClearHeld ();
+
// Do not send back to input stream
return false;
}
@@ -239,14 +239,15 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
}
///
- ///
- /// When overriden in a derived class, indicates whether the unexpected response
- /// currently in should be released or swallowed.
- /// Use this to enable default event for escape codes.
- ///
- ///
- /// Note this is only called for complete responses.
- /// Based on
+ ///
+ /// When overriden in a derived class, indicates whether the unexpected response
+ /// currently in should be released or swallowed.
+ /// Use this to enable default event for escape codes.
+ ///
+ ///
+ /// Note this is only called for complete responses.
+ /// Based on
+ ///
///
///
protected abstract bool ShouldSwallowUnexpectedResponse ();
@@ -254,7 +255,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
private bool MatchResponse (string cur, List collection, bool invokeCallback, bool removeExpectation)
{
// Check for expected responses
- var matchingResponse = collection.FirstOrDefault (r => r.Matches (cur));
+ AnsiResponseExpectation? matchingResponse = collection.FirstOrDefault (r => r.Matches (cur));
if (matchingResponse?.Response != null)
{
@@ -262,6 +263,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
{
matchingResponse.Response.Invoke (heldContent);
}
+
ResetState ();
if (removeExpectation)
@@ -275,23 +277,23 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
return false;
}
- ///
+ ///
public void ExpectResponse (string terminator, Action response, bool persistent)
{
lock (lockExpectedResponses)
{
if (persistent)
{
- persistentExpectations.Add (new (terminator, (h) => response.Invoke (h.HeldToString ())));
+ persistentExpectations.Add (new (terminator, h => response.Invoke (h.HeldToString ())));
}
else
{
- expectedResponses.Add (new (terminator, (h) => response.Invoke (h.HeldToString ())));
+ expectedResponses.Add (new (terminator, h => response.Invoke (h.HeldToString ())));
}
}
}
- ///
+ ///
public bool IsExpecting (string terminator)
{
lock (lockExpectedResponses)
@@ -301,10 +303,9 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
}
}
- ///
+ ///
public void StopExpecting (string terminator, bool persistent)
{
-
lock (lockExpectedResponses)
{
if (persistent)
@@ -313,9 +314,9 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
}
else
{
- var removed = expectedResponses.Where (r => r.Terminator == terminator).ToArray ();
+ AnsiResponseExpectation [] removed = expectedResponses.Where (r => r.Terminator == terminator).ToArray ();
- foreach (var r in removed)
+ foreach (AnsiResponseExpectation r in removed)
{
expectedResponses.Remove (r);
lateResponses.Add (r);
@@ -329,14 +330,12 @@ internal class AnsiResponseParser : AnsiResponseParserBase
{
public AnsiResponseParser () : base (new GenericHeld ()) { }
-
///
- public Func>, bool> UnexpectedResponseHandler { get; set; } = (_) => false;
-
+ public Func>, bool> UnexpectedResponseHandler { get; set; } = _ => false;
public IEnumerable> ProcessInput (params Tuple [] input)
{
- List> output = new List> ();
+ List> output = new ();
ProcessInputBase (
i => input [i].Item1,
@@ -352,64 +351,57 @@ internal class AnsiResponseParser : AnsiResponseParserBase
// Lock in case Release is called from different Thread from parse
lock (lockState)
{
- foreach (Tuple h in HeldToEnumerable())
+ foreach (Tuple h in HeldToEnumerable ())
{
yield return h;
}
ResetState ();
}
-
}
- private IEnumerable> HeldToEnumerable ()
- {
- return (IEnumerable>)heldContent.HeldToObjects ();
- }
+ private IEnumerable> HeldToEnumerable () { return (IEnumerable>)heldContent.HeldToObjects (); }
///
- /// 'Overload' for specifying an expectation that requires the metadata as well as characters. Has
- /// a unique name because otherwise most lamdas will give ambiguous overload errors.
+ /// 'Overload' for specifying an expectation that requires the metadata as well as characters. Has
+ /// a unique name because otherwise most lamdas will give ambiguous overload errors.
///
///
///
///
- public void ExpectResponseT (string terminator, Action>> response, bool persistent)
+ public void ExpectResponseT (string terminator, Action>> response, bool persistent)
{
lock (lockExpectedResponses)
{
if (persistent)
{
- persistentExpectations.Add (new (terminator, (h) => response.Invoke (HeldToEnumerable ())));
+ persistentExpectations.Add (new (terminator, h => response.Invoke (HeldToEnumerable ())));
}
else
{
- expectedResponses.Add (new (terminator, (h) => response.Invoke (HeldToEnumerable ())));
+ expectedResponses.Add (new (terminator, h => response.Invoke (HeldToEnumerable ())));
}
}
}
- ///
- protected override bool ShouldSwallowUnexpectedResponse ()
- {
- return UnexpectedResponseHandler.Invoke (HeldToEnumerable ());
- }
+ ///
+ protected override bool ShouldSwallowUnexpectedResponse () { return UnexpectedResponseHandler.Invoke (HeldToEnumerable ()); }
}
internal class AnsiResponseParser : AnsiResponseParserBase
{
///
- ///
- /// Delegate for handling unrecognized escape codes. Default behaviour
- /// is to return which simply releases the
- /// characters back to input stream for downstream processing.
- ///
- ///
- /// Implement a method to handle if you want and return if you want the
- /// keystrokes 'swallowed' (i.e. not returned to input stream).
- ///
+ ///
+ /// Delegate for handling unrecognized escape codes. Default behaviour
+ /// is to return which simply releases the
+ /// characters back to input stream for downstream processing.
+ ///
+ ///
+ /// Implement a method to handle if you want and return if you want the
+ /// keystrokes 'swallowed' (i.e. not returned to input stream).
+ ///
///
- public Func UnknownResponseHandler { get; set; } = (_) => false;
+ public Func UnknownResponseHandler { get; set; } = _ => false;
public AnsiResponseParser () : base (new StringHeld ()) { }
@@ -430,16 +422,13 @@ internal class AnsiResponseParser : AnsiResponseParserBase
{
lock (lockState)
{
- var output = heldContent.HeldToString ();
+ string output = heldContent.HeldToString ();
ResetState ();
return output;
}
}
- ///
- protected override bool ShouldSwallowUnexpectedResponse ()
- {
- return UnknownResponseHandler.Invoke (heldContent.HeldToString ());
- }
-}
\ No newline at end of file
+ ///
+ protected override bool ShouldSwallowUnexpectedResponse () { return UnknownResponseHandler.Invoke (heldContent.HeldToString ()); }
+}
diff --git a/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/GenericHeld.cs b/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/GenericHeld.cs
index c81cb6565..ffd8d4689 100644
--- a/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/GenericHeld.cs
+++ b/Terminal.Gui/ConsoleDrivers/AnsiResponseParser/GenericHeld.cs
@@ -2,15 +2,18 @@
namespace Terminal.Gui;
///
-/// Implementation of for
+/// Implementation of for
///
///
internal class GenericHeld : IHeld
{
private readonly List> held = new ();
- public void ClearHeld () => held.Clear ();
- public string HeldToString () => new (held.Select (h => h.Item1).ToArray ());
- public IEnumerable