|
@@ -1,7 +1,5 @@
|
|
|
#nullable enable
|
|
|
|
|
|
-using System.Runtime.ConstrainedExecution;
|
|
|
-
|
|
|
namespace Terminal.Gui;
|
|
|
|
|
|
|
|
@@ -36,6 +34,8 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ protected readonly IHeld heldContent;
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// When <see cref="State"/> was last changed.
|
|
|
/// </summary>
|
|
@@ -55,18 +55,17 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
|
|
|
});
|
|
|
|
|
|
+ protected AnsiResponseParserBase (IHeld heldContent)
|
|
|
+ {
|
|
|
+ this.heldContent = heldContent;
|
|
|
+ }
|
|
|
|
|
|
protected void ResetState ()
|
|
|
{
|
|
|
State = AnsiResponseParserState.Normal;
|
|
|
- ClearHeld ();
|
|
|
+ heldContent.ClearHeld ();
|
|
|
}
|
|
|
|
|
|
- public abstract void ClearHeld ();
|
|
|
- protected abstract string HeldToString ();
|
|
|
- protected abstract IEnumerable<object> HeldToObjects ();
|
|
|
- protected abstract void AddToHeld (object o);
|
|
|
-
|
|
|
/// <summary>
|
|
|
/// Processes an input collection of objects <paramref name="inputLength"/> long.
|
|
|
/// You must provide the indexers to return the objects and the action to append
|
|
@@ -102,7 +101,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
{
|
|
|
// Escape character detected, move to ExpectingBracket state
|
|
|
State = AnsiResponseParserState.ExpectingBracket;
|
|
|
- AddToHeld (currentObj); // Hold the escape character
|
|
|
+ heldContent.AddToHeld (currentObj); // Hold the escape character
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -117,13 +116,13 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
{
|
|
|
// Second escape so we must release first
|
|
|
ReleaseHeld (appendOutput, AnsiResponseParserState.ExpectingBracket);
|
|
|
- AddToHeld (currentObj); // Hold the new escape
|
|
|
+ heldContent.AddToHeld (currentObj); // Hold the new escape
|
|
|
}
|
|
|
else if (currentChar == '[')
|
|
|
{
|
|
|
// Detected '[', transition to InResponse state
|
|
|
State = AnsiResponseParserState.InResponse;
|
|
|
- AddToHeld (currentObj); // Hold the '['
|
|
|
+ heldContent.AddToHeld (currentObj); // Hold the '['
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -135,7 +134,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
break;
|
|
|
|
|
|
case AnsiResponseParserState.InResponse:
|
|
|
- AddToHeld (currentObj);
|
|
|
+ heldContent.AddToHeld (currentObj);
|
|
|
|
|
|
// Check if the held content should be released
|
|
|
if (ShouldReleaseHeldContent ())
|
|
@@ -152,25 +151,25 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
|
|
|
private void ReleaseHeld (Action<object> appendOutput, AnsiResponseParserState newState = AnsiResponseParserState.Normal)
|
|
|
{
|
|
|
- foreach (object o in HeldToObjects ())
|
|
|
+ foreach (object o in heldContent.HeldToObjects ())
|
|
|
{
|
|
|
appendOutput (o);
|
|
|
}
|
|
|
|
|
|
State = newState;
|
|
|
- ClearHeld ();
|
|
|
+ heldContent.ClearHeld ();
|
|
|
}
|
|
|
|
|
|
// Common response handler logic
|
|
|
protected bool ShouldReleaseHeldContent ()
|
|
|
{
|
|
|
- string cur = HeldToString ();
|
|
|
+ string cur = heldContent.HeldToString ();
|
|
|
|
|
|
// Look for an expected response for what is accumulated so far (since Esc)
|
|
|
if (MatchResponse (cur,
|
|
|
expectedResponses,
|
|
|
invokeCallback: true,
|
|
|
- removeExpectation:true))
|
|
|
+ removeExpectation: true))
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
@@ -179,7 +178,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
if (MatchResponse (cur,
|
|
|
lateResponses,
|
|
|
invokeCallback: false,
|
|
|
- removeExpectation:true))
|
|
|
+ removeExpectation: true))
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
@@ -188,7 +187,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
if (MatchResponse (cur,
|
|
|
persistentExpectations,
|
|
|
invokeCallback: true,
|
|
|
- removeExpectation:false))
|
|
|
+ removeExpectation: false))
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
@@ -208,13 +207,13 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
private bool MatchResponse (string cur, List<AnsiResponseExpectation> collection, bool invokeCallback, bool removeExpectation)
|
|
|
{
|
|
|
// Check for expected responses
|
|
|
- var matchingResponse = collection.FirstOrDefault (r => r.Matches(cur));
|
|
|
+ var matchingResponse = collection.FirstOrDefault (r => r.Matches (cur));
|
|
|
|
|
|
if (matchingResponse?.Response != null)
|
|
|
{
|
|
|
if (invokeCallback)
|
|
|
{
|
|
|
- matchingResponse.Response?.Invoke (HeldToString ());
|
|
|
+ matchingResponse.Response.Invoke (heldContent);
|
|
|
}
|
|
|
ResetState ();
|
|
|
|
|
@@ -234,11 +233,11 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
{
|
|
|
if (persistent)
|
|
|
{
|
|
|
- persistentExpectations.Add (new (terminator, response));
|
|
|
+ persistentExpectations.Add (new (terminator, (h)=>response.Invoke (h.HeldToString ())));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- expectedResponses.Add (new (terminator, response));
|
|
|
+ expectedResponses.Add (new (terminator, (h) => response.Invoke (h.HeldToString ())));
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -246,7 +245,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
public bool IsExpecting (string terminator)
|
|
|
{
|
|
|
// 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 />
|
|
@@ -254,7 +253,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
{
|
|
|
if (persistent)
|
|
|
{
|
|
|
- persistentExpectations.RemoveAll (r=>r.Matches (terminator));
|
|
|
+ persistentExpectations.RemoveAll (r => r.Matches (terminator));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -271,7 +270,7 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
|
|
|
|
internal class AnsiResponseParser<T> : AnsiResponseParserBase
|
|
|
{
|
|
|
- private readonly List<Tuple<char, T>> held = new ();
|
|
|
+ public AnsiResponseParser () : base (new GenericHeld<T> ()) { }
|
|
|
|
|
|
public IEnumerable<Tuple<char, T>> ProcessInput (params Tuple<char, T> [] input)
|
|
|
{
|
|
@@ -288,7 +287,7 @@ internal class AnsiResponseParser<T> : AnsiResponseParserBase
|
|
|
|
|
|
public IEnumerable<Tuple<char, T>> Release ()
|
|
|
{
|
|
|
- foreach (Tuple<char, T> h in held.ToArray ())
|
|
|
+ foreach (Tuple<char, T> h in HeldToEnumerable())
|
|
|
{
|
|
|
yield return h;
|
|
|
}
|
|
@@ -296,18 +295,34 @@ internal class AnsiResponseParser<T> : AnsiResponseParserBase
|
|
|
ResetState ();
|
|
|
}
|
|
|
|
|
|
- public override void ClearHeld () { held.Clear (); }
|
|
|
-
|
|
|
- protected override string HeldToString () { return new (held.Select (h => h.Item1).ToArray ()); }
|
|
|
-
|
|
|
- protected override IEnumerable<object> HeldToObjects () { return held; }
|
|
|
+ private IEnumerable<Tuple<char, T>> HeldToEnumerable ()
|
|
|
+ {
|
|
|
+ return (IEnumerable<Tuple<char, T>>)heldContent.HeldToObjects ();
|
|
|
+ }
|
|
|
|
|
|
- protected override void AddToHeld (object o) { held.Add ((Tuple<char, T>)o); }
|
|
|
+ /// <summary>
|
|
|
+ /// '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.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="terminator"></param>
|
|
|
+ /// <param name="response"></param>
|
|
|
+ /// <param name="persistent"></param>
|
|
|
+ public void ExpectResponseT (string terminator, Action<IEnumerable<Tuple<char,T>>> response, bool persistent)
|
|
|
+ {
|
|
|
+ if (persistent)
|
|
|
+ {
|
|
|
+ persistentExpectations.Add (new (terminator, (h) => response.Invoke (HeldToEnumerable ())));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ expectedResponses.Add (new (terminator, (h) => response.Invoke (HeldToEnumerable ())));
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
internal class AnsiResponseParser : AnsiResponseParserBase
|
|
|
{
|
|
|
- private readonly StringBuilder held = new ();
|
|
|
+ public AnsiResponseParser () : base (new StringHeld ()) { }
|
|
|
|
|
|
public string ProcessInput (string input)
|
|
|
{
|
|
@@ -324,17 +339,9 @@ internal class AnsiResponseParser : AnsiResponseParserBase
|
|
|
|
|
|
public string Release ()
|
|
|
{
|
|
|
- var output = held.ToString ();
|
|
|
+ var output = heldContent.HeldToString ();
|
|
|
ResetState ();
|
|
|
|
|
|
return output;
|
|
|
}
|
|
|
-
|
|
|
- public override void ClearHeld () { held.Clear (); }
|
|
|
-
|
|
|
- protected override string HeldToString () { return held.ToString (); }
|
|
|
-
|
|
|
- protected override IEnumerable<object> HeldToObjects () { return held.ToString ().Select (c => (object)c).ToArray (); }
|
|
|
-
|
|
|
- protected override void AddToHeld (object o) { held.Append ((char)o); }
|
|
|
}
|