NetOutput.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. using Microsoft.Extensions.Logging;
  2. namespace Terminal.Gui.Drivers;
  3. /// <summary>
  4. /// Implementation of <see cref="IConsoleOutput"/> that uses native dotnet
  5. /// methods e.g. <see cref="System.Console"/>
  6. /// </summary>
  7. public class NetOutput : OutputBase, IConsoleOutput
  8. {
  9. private readonly bool _isWinPlatform;
  10. /// <summary>
  11. /// Creates a new instance of the <see cref="NetOutput"/> class.
  12. /// </summary>
  13. public NetOutput ()
  14. {
  15. Logging.Logger.LogInformation ($"Creating {nameof (NetOutput)}");
  16. Console.OutputEncoding = Encoding.UTF8;
  17. PlatformID p = Environment.OSVersion.Platform;
  18. if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows)
  19. {
  20. _isWinPlatform = true;
  21. }
  22. }
  23. /// <inheritdoc/>
  24. public void Write (ReadOnlySpan<char> text)
  25. {
  26. Console.Out.Write (text);
  27. }
  28. /// <inheritdoc/>
  29. public Size GetSize ()
  30. {
  31. if (ConsoleDriver.RunningUnitTests)
  32. {
  33. // For unit tests, we return a default size.
  34. return Size.Empty;
  35. }
  36. return new (Console.WindowWidth, Console.WindowHeight);
  37. }
  38. /// <inheritdoc/>
  39. public void SetCursorPosition (int col, int row) { SetCursorPositionImpl (col, row); }
  40. /// <inheritdoc />
  41. public void SetSize (int width, int height)
  42. {
  43. // Do Nothing.
  44. }
  45. private Point? _lastCursorPosition;
  46. /// <inheritdoc/>
  47. protected override void AppendOrWriteAttribute (StringBuilder output, Attribute attr, TextStyle redrawTextStyle)
  48. {
  49. if (Application.Force16Colors)
  50. {
  51. output.Append (EscSeqUtils.CSI_SetForegroundColor (attr.Foreground.GetAnsiColorCode ()));
  52. output.Append (EscSeqUtils.CSI_SetBackgroundColor (attr.Background.GetAnsiColorCode ()));
  53. }
  54. else
  55. {
  56. EscSeqUtils.CSI_AppendForegroundColorRGB (
  57. output,
  58. attr.Foreground.R,
  59. attr.Foreground.G,
  60. attr.Foreground.B
  61. );
  62. EscSeqUtils.CSI_AppendBackgroundColorRGB (
  63. output,
  64. attr.Background.R,
  65. attr.Background.G,
  66. attr.Background.B
  67. );
  68. }
  69. EscSeqUtils.CSI_AppendTextStyleChange (output, redrawTextStyle, attr.Style);
  70. }
  71. /// <inheritdoc />
  72. protected override void Write (StringBuilder output)
  73. {
  74. Console.Out.Write (output);
  75. }
  76. /// <inheritdoc />
  77. protected override bool SetCursorPositionImpl (int col, int row)
  78. {
  79. if (_lastCursorPosition is { } && _lastCursorPosition.Value.X == col && _lastCursorPosition.Value.Y == row)
  80. {
  81. return true;
  82. }
  83. _lastCursorPosition = new (col, row);
  84. if (_isWinPlatform)
  85. {
  86. // Could happens that the windows is still resizing and the col is bigger than Console.WindowWidth.
  87. try
  88. {
  89. Console.SetCursorPosition (col, row);
  90. return true;
  91. }
  92. catch (Exception)
  93. {
  94. return false;
  95. }
  96. }
  97. // + 1 is needed because non-Windows is based on 1 instead of 0 and
  98. // Console.CursorTop/CursorLeft isn't reliable.
  99. EscSeqUtils.CSI_WriteCursorPosition (Console.Out, row + 1, col + 1);
  100. return true;
  101. }
  102. /// <inheritdoc/>
  103. public void Dispose ()
  104. {
  105. }
  106. private EscSeqUtils.DECSCUSR_Style? _currentDecscusrStyle;
  107. /// <inheritdoc cref="IConsoleOutput.SetCursorVisibility"/>
  108. public override void SetCursorVisibility (CursorVisibility visibility)
  109. {
  110. if (visibility != CursorVisibility.Invisible)
  111. {
  112. if (_currentDecscusrStyle is null || _currentDecscusrStyle != (EscSeqUtils.DECSCUSR_Style)(((int)visibility >> 24) & 0xFF))
  113. {
  114. _currentDecscusrStyle = (EscSeqUtils.DECSCUSR_Style)(((int)visibility >> 24) & 0xFF);
  115. Write (EscSeqUtils.CSI_SetCursorStyle ((EscSeqUtils.DECSCUSR_Style)_currentDecscusrStyle));
  116. }
  117. Write (EscSeqUtils.CSI_ShowCursor);
  118. }
  119. else
  120. {
  121. Write (EscSeqUtils.CSI_HideCursor);
  122. }
  123. }
  124. }