You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
4.4 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace IPA.Logging.Printers
  4. {
  5. /// <summary>
  6. /// Prints a pretty message to the console.
  7. /// </summary>
  8. public class ColoredConsolePrinter : LogPrinter
  9. {
  10. private Logger.LogLevel filter = Logger.LogLevel.All;
  11. /// <summary>
  12. /// A filter for this specific printer.
  13. /// </summary>
  14. /// <value>the filter to apply to this printer</value>
  15. public override Logger.LogLevel Filter { get => filter; set => filter = value; }
  16. /// <summary>
  17. /// The color to print messages as.
  18. /// </summary>
  19. /// <value>the color to print this message as</value>
  20. // Initializer calls this function because Unity's .NET 3.5 doesn't have the color properties on Console
  21. // TODO: move this garbo out to Net3_Proxy
  22. public ConsoleColor Color { get; set; } = GetConsoleColor(WinConsole.OutHandle);
  23. /// <summary>
  24. /// Prints an entry to the console window.
  25. /// </summary>
  26. /// <param name="level">the <see cref="Logger.Level"/> of the message</param>
  27. /// <param name="time">the <see cref="DateTime"/> the message was recorded at</param>
  28. /// <param name="logName">the name of the log that sent the message</param>
  29. /// <param name="message">the message to print</param>
  30. public override void Print(Logger.Level level, DateTime time, string logName, string message)
  31. {
  32. if (((byte)level & (byte)StandardLogger.PrintFilter) == 0) return;
  33. EnsureDefaultsPopulated(WinConsole.OutHandle);
  34. SetColor(Color, WinConsole.OutHandle);
  35. foreach (var line in message.Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
  36. WinConsole.ConOut.WriteLine(Logger.LogFormat, line, logName, time, level.ToString().ToUpper());
  37. ResetColor(WinConsole.OutHandle);
  38. }
  39. private static bool _haveReadDefaultColors;
  40. private static short _defaultColors;
  41. private void EnsureDefaultsPopulated(IntPtr handle, bool force = false)
  42. {
  43. if (!_haveReadDefaultColors | force)
  44. {
  45. GetConsoleScreenBufferInfo(handle, out var info);
  46. _defaultColors = (short)(info.Attribute & ~15);
  47. _haveReadDefaultColors = true;
  48. }
  49. }
  50. private void ResetColor(IntPtr handle)
  51. {
  52. GetConsoleScreenBufferInfo(handle, out var info);
  53. var otherAttrs = (short)(info.Attribute & ~15);
  54. SetConsoleTextAttribute(handle, (short)(otherAttrs | _defaultColors));
  55. }
  56. private void SetColor(ConsoleColor col, IntPtr handle)
  57. {
  58. GetConsoleScreenBufferInfo(handle, out var info);
  59. var attr = GetAttrForeground(info.Attribute, col);
  60. SetConsoleTextAttribute(handle, attr);
  61. }
  62. private static short GetAttrForeground(int attr, ConsoleColor color)
  63. {
  64. attr &= ~15;
  65. return (short)(attr | (int)color);
  66. }
  67. private static ConsoleColor GetConsoleColor(IntPtr handle)
  68. {
  69. GetConsoleScreenBufferInfo(handle, out var info);
  70. return (ConsoleColor)(info.Attribute & 15);
  71. }
  72. // ReSharper disable NotAccessedField.Local
  73. #pragma warning disable 649
  74. private struct Coordinate
  75. {
  76. public short X;
  77. public short Y;
  78. }
  79. private struct SmallRect
  80. {
  81. public short Left;
  82. public short Top;
  83. public short Right;
  84. public short Bottom;
  85. }
  86. private struct ConsoleScreenBufferInfo
  87. {
  88. public Coordinate Size;
  89. public Coordinate CursorPosition;
  90. public short Attribute;
  91. public SmallRect Window;
  92. public Coordinate MaxWindowSize;
  93. }
  94. #pragma warning restore 649
  95. // ReSharper restore NotAccessedField.Local
  96. [DllImport("kernel32.dll", EntryPoint = "GetConsoleScreenBufferInfo", SetLastError = true, CharSet = CharSet.Unicode)]
  97. private static extern bool GetConsoleScreenBufferInfo(IntPtr handle, out ConsoleScreenBufferInfo info);
  98. [DllImport("kernel32.dll", EntryPoint = "SetConsoleTextAttribute", SetLastError = true, CharSet = CharSet.Unicode)]
  99. private static extern bool SetConsoleTextAttribute(IntPtr handle, short attribute);
  100. }
  101. }