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.

116 lines
4.4 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 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. public ConsoleColor Color { get; set; } = GetConsoleColor(WinConsole.OutHandle);
  22. /// <summary>
  23. /// Prints an entry to the console window.
  24. /// </summary>
  25. /// <param name="level">the <see cref="Logger.Level"/> of the message</param>
  26. /// <param name="time">the <see cref="DateTime"/> the message was recorded at</param>
  27. /// <param name="logName">the name of the log that sent the message</param>
  28. /// <param name="message">the message to print</param>
  29. public override void Print(Logger.Level level, DateTime time, string logName, string message)
  30. {
  31. if (((byte)level & (byte)StandardLogger.PrintFilter) == 0) return;
  32. EnsureDefaultsPopulated(WinConsole.OutHandle);
  33. SetColor(Color, WinConsole.OutHandle);
  34. foreach (var line in message.Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
  35. WinConsole.ConOut.WriteLine(Logger.LogFormat, line, logName, time, level.ToString().ToUpper());
  36. ResetColor(WinConsole.OutHandle);
  37. }
  38. private static bool _haveReadDefaultColors;
  39. private static short _defaultColors;
  40. private void EnsureDefaultsPopulated(IntPtr handle, bool force = false)
  41. {
  42. if (!_haveReadDefaultColors | force)
  43. {
  44. GetConsoleScreenBufferInfo(handle, out var info);
  45. _defaultColors = (short)(info.Attribute & ~15);
  46. _haveReadDefaultColors = true;
  47. }
  48. }
  49. private void ResetColor(IntPtr handle)
  50. {
  51. GetConsoleScreenBufferInfo(handle, out var info);
  52. var otherAttrs = (short)(info.Attribute & ~15);
  53. SetConsoleTextAttribute(handle, (short)(otherAttrs | _defaultColors));
  54. }
  55. private void SetColor(ConsoleColor col, IntPtr handle)
  56. {
  57. GetConsoleScreenBufferInfo(handle, out var info);
  58. var attr = GetAttrForeground(info.Attribute, col);
  59. SetConsoleTextAttribute(handle, attr);
  60. }
  61. private static short GetAttrForeground(int attr, ConsoleColor color)
  62. {
  63. attr &= ~15;
  64. return (short)(attr | (int)color);
  65. }
  66. private static ConsoleColor GetConsoleColor(IntPtr handle)
  67. {
  68. GetConsoleScreenBufferInfo(handle, out var info);
  69. return (ConsoleColor)(info.Attribute & 15);
  70. }
  71. // ReSharper disable NotAccessedField.Local
  72. #pragma warning disable 649
  73. private struct Coordinate
  74. {
  75. public short X;
  76. public short Y;
  77. }
  78. private struct SmallRect
  79. {
  80. public short Left;
  81. public short Top;
  82. public short Right;
  83. public short Bottom;
  84. }
  85. private struct ConsoleScreenBufferInfo
  86. {
  87. public Coordinate Size;
  88. public Coordinate CursorPosition;
  89. public short Attribute;
  90. public SmallRect Window;
  91. public Coordinate MaxWindowSize;
  92. }
  93. #pragma warning restore 649
  94. // ReSharper restore NotAccessedField.Local
  95. [DllImport("kernel32.dll", EntryPoint = "GetConsoleScreenBufferInfo", SetLastError = true, CharSet = CharSet.Unicode)]
  96. private static extern bool GetConsoleScreenBufferInfo(IntPtr handle, out ConsoleScreenBufferInfo info);
  97. [DllImport("kernel32.dll", EntryPoint = "SetConsoleTextAttribute", SetLastError = true, CharSet = CharSet.Unicode)]
  98. private static extern bool SetConsoleTextAttribute(IntPtr handle, short attribute);
  99. }
  100. }