EscSeqReq.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. using System;
  2. using System.Collections.Generic;
  3. namespace Terminal.Gui {
  4. /// <summary>
  5. /// Represents the status of an ANSI escape sequence request made to the terminal using <see cref="EscSeqRequests"/>.
  6. /// </summary>
  7. /// <remarks>
  8. /// </remarks>
  9. public class EscSeqReqStatus {
  10. /// <summary>
  11. /// Gets the Escape Sequence Termintor (e.g. ESC[8t ... t is the terminator).
  12. /// </summary>
  13. public string Terminator { get; }
  14. /// <summary>
  15. /// Gets the number of requests.
  16. /// </summary>
  17. public int NumRequests { get; }
  18. /// <summary>
  19. /// Gets the number of unfinished requests.
  20. /// </summary>
  21. public int NumOutstanding { get; set; }
  22. /// <summary>
  23. /// Creates a new state of escape sequence request.
  24. /// </summary>
  25. /// <param name="terminator">The terminator.</param>
  26. /// <param name="numReq">The number of requests.</param>
  27. public EscSeqReqStatus (string terminator, int numReq)
  28. {
  29. Terminator = terminator;
  30. NumRequests = NumOutstanding = numReq;
  31. }
  32. }
  33. // TODO: This class is a singleton. It should use the singleton pattern.
  34. /// <summary>
  35. /// Manages ANSI Escape Sequence requests and responses. The list of <see cref="EscSeqReqStatus"/> contains the status of the request.
  36. /// Each request is identified by the terminator (e.g. ESC[8t ... t is the terminator).
  37. /// </summary>
  38. public class EscSeqRequests {
  39. /// <summary>
  40. /// Gets the <see cref="EscSeqReqStatus"/> list.
  41. /// </summary>
  42. public List<EscSeqReqStatus> Statuses { get; } = new List<EscSeqReqStatus> ();
  43. /// <summary>
  44. /// Adds a new request for the ANSI Escape Sequence defined by <paramref name="terminator"/>. Adds a <see cref="EscSeqReqStatus"/>
  45. /// instance to <see cref="Statuses"/> list.
  46. /// </summary>
  47. /// <param name="terminator">The terminator.</param>
  48. /// <param name="numReq">The number of requests.</param>
  49. public void Add (string terminator, int numReq = 1)
  50. {
  51. lock (Statuses) {
  52. var found = Statuses.Find (x => x.Terminator == terminator);
  53. if (found == null) {
  54. Statuses.Add (new EscSeqReqStatus (terminator, numReq));
  55. } else if (found != null && found.NumOutstanding < found.NumRequests) {
  56. found.NumOutstanding = Math.Min (found.NumOutstanding + numReq, found.NumRequests);
  57. }
  58. }
  59. }
  60. /// <summary>
  61. /// Removes a request defined by <paramref name="terminator"/>. If a matching <see cref="EscSeqReqStatus"/> is found
  62. /// and the number of outstanding
  63. /// requests is greater than 0, the number of outstanding requests is decremented. If the number of outstanding requests
  64. /// is 0, the <see cref="EscSeqReqStatus"/> is removed from <see cref="Statuses"/>.
  65. /// </summary>
  66. /// <param name="terminator">The terminating string.</param>
  67. public void Remove (string terminator)
  68. {
  69. lock (Statuses) {
  70. var found = Statuses.Find (x => x.Terminator == terminator);
  71. if (found == null) {
  72. return;
  73. }
  74. if (found != null && found.NumOutstanding == 0) {
  75. Statuses.Remove (found);
  76. } else if (found != null && found.NumOutstanding > 0) {
  77. found.NumOutstanding--;
  78. if (found.NumOutstanding == 0) {
  79. Statuses.Remove (found);
  80. }
  81. }
  82. }
  83. }
  84. /// <summary>
  85. /// Indicates if a <see cref="EscSeqReqStatus"/> with the <paramref name="terminator"/> exists
  86. /// in the <see cref="Statuses"/> list.
  87. /// </summary>
  88. /// <param name="terminator"></param>
  89. /// <returns><see langword="true"/> if exist, <see langword="false"/> otherwise.</returns>
  90. public bool HasResponse (string terminator)
  91. {
  92. lock (Statuses) {
  93. var found = Statuses.Find (x => x.Terminator == terminator);
  94. if (found == null) {
  95. return false;
  96. }
  97. if (found != null && found.NumOutstanding > 0) {
  98. return true;
  99. } else {
  100. // BUGBUG: Why does an API that returns a bool remove the entry from the list?
  101. // NetDriver and Unit tests never exercise this line of code. Maybe Curses does?
  102. Statuses.Remove (found);
  103. }
  104. return false;
  105. }
  106. }
  107. }
  108. }