Merge pull request #418 from waf/fix-parser-and-registry-bugs-with-refactor
Fix ColorTool parser and registry bugs, and refactor
This commit is contained in:
commit
723efc70e2
|
@ -1,31 +1,74 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace ColorTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a colorscheme that can be applied to a console.
|
||||
/// </summary>
|
||||
public class ColorScheme
|
||||
{
|
||||
public uint[] colorTable = null;
|
||||
public ConsoleAttributes consoleAttributes;
|
||||
public ColorScheme(uint[] colorTable, ConsoleAttributes consoleAttributes)
|
||||
{
|
||||
ColorTable = colorTable;
|
||||
ConsoleAttributes = consoleAttributes;
|
||||
}
|
||||
|
||||
public uint[] ColorTable { get; }
|
||||
public ConsoleAttributes ConsoleAttributes { get; }
|
||||
|
||||
public ushort? ScreenColorAttributes =>
|
||||
CalculateBackgroundForegroundAttributes(
|
||||
this.ConsoleAttributes.Background,
|
||||
this.ConsoleAttributes.Foreground
|
||||
);
|
||||
|
||||
public ushort? PopupColorAttributes =>
|
||||
CalculateBackgroundForegroundAttributes(
|
||||
this.ConsoleAttributes.PopupBackground,
|
||||
this.ConsoleAttributes.PopupForeground
|
||||
);
|
||||
|
||||
public Color this[int index] => UIntToColor(ColorTable[index]);
|
||||
|
||||
private static Color UIntToColor(uint color)
|
||||
{
|
||||
byte r = (byte)(color >> 0);
|
||||
byte g = (byte)(color >> 8);
|
||||
byte b = (byte)(color >> 16);
|
||||
return Color.FromArgb(r, g, b);
|
||||
}
|
||||
|
||||
private ushort? CalculateBackgroundForegroundAttributes(uint? background, uint? foreground)
|
||||
{
|
||||
if(!(background.HasValue && foreground.HasValue))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
int fgidx = this.CalculateIndex(foreground.Value);
|
||||
int bgidx = this.CalculateIndex(background.Value);
|
||||
var attributes = (ushort)(fgidx | (bgidx << 4));
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public int CalculateIndex(uint value) =>
|
||||
colorTable.Select((color, idx) => Tuple.Create(color, idx))
|
||||
ColorTable.Select((color, idx) => Tuple.Create(color, idx))
|
||||
.OrderBy(Difference(value))
|
||||
.First().Item2;
|
||||
|
||||
private static Func<Tuple<uint, int>, double> Difference(uint c1) =>
|
||||
// heuristic 1: nearest neighbor in RGB space
|
||||
// tup => Distance(RGB(c1), RGB(tup.Item1));
|
||||
// heuristic 2: nearest neighbor in RGB space
|
||||
// tup => Distance(HSV(c1), HSV(tup.Item1));
|
||||
// heuristic 3: weighted RGB L2 distance
|
||||
tup => WeightedRGBSimilarity(c1, tup.Item1);
|
||||
// heuristic 1: nearest neighbor in RGB space
|
||||
// tup => Distance(RGB(c1), RGB(tup.Item1));
|
||||
// heuristic 2: nearest neighbor in RGB space
|
||||
// tup => Distance(HSV(c1), HSV(tup.Item1));
|
||||
// heuristic 3: weighted RGB L2 distance
|
||||
tup => WeightedRGBSimilarity(c1, tup.Item1);
|
||||
|
||||
private static double WeightedRGBSimilarity(uint c1, uint c2)
|
||||
{
|
||||
|
@ -36,9 +79,6 @@ namespace ColorTool
|
|||
return Math.Sqrt(dist[0] * (2 + rbar / 256.0) + dist[1] * 4 + dist[2] * (2 + (255 - rbar) / 256.0));
|
||||
}
|
||||
|
||||
private static double Distance(uint[] c1c, uint[] c2c)
|
||||
=> Math.Sqrt(c1c.Zip(c2c, (a, b) => Math.Pow((int)a - (int)b, 2)).Sum());
|
||||
|
||||
internal static uint[] RGB(uint c) => new[] { c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF };
|
||||
|
||||
internal static uint[] HSV(uint c)
|
||||
|
@ -77,17 +117,17 @@ namespace ColorTool
|
|||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
_dump($"Color[{i}]", colorTable[i]);
|
||||
_dump($"Color[{i}]", ColorTable[i]);
|
||||
}
|
||||
|
||||
if (consoleAttributes.foreground != null)
|
||||
if (ConsoleAttributes.Foreground != null)
|
||||
{
|
||||
_dump("FG ", consoleAttributes.foreground.Value);
|
||||
_dump("FG ", ConsoleAttributes.Foreground.Value);
|
||||
}
|
||||
|
||||
if (consoleAttributes.background != null)
|
||||
if (ConsoleAttributes.Background != null)
|
||||
{
|
||||
_dump("BG ", consoleAttributes.background.Value);
|
||||
_dump("BG ", ConsoleAttributes.Background.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
205
tools/ColorTool/ColorTool/ColorTable.cs
Normal file
205
tools/ColorTool/ColorTool/ColorTable.cs
Normal file
|
@ -0,0 +1,205 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ColorTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Displays the color table that demonstrates the current colorscheme.
|
||||
/// </summary>
|
||||
static class ColorTable
|
||||
{
|
||||
private const int DarkBlack = 0;
|
||||
private const int DarkBlue = 1;
|
||||
private const int DarkGreen = 2;
|
||||
private const int DarkCyan = 3;
|
||||
private const int DarkRed = 4;
|
||||
private const int DarkMagenta = 5;
|
||||
private const int DarkYellow = 6;
|
||||
private const int DarkWhite = 7;
|
||||
private const int BrightBlack = 8;
|
||||
private const int BrightBlue = 9;
|
||||
private const int BrightGreen = 10;
|
||||
private const int BrightCyan = 11;
|
||||
private const int BrightRed = 12;
|
||||
private const int BrightMagenta = 13;
|
||||
private const int BrightYellow = 14;
|
||||
private const int BrightWhite = 15;
|
||||
|
||||
// This is the order of colors when output by the table.
|
||||
private static readonly IReadOnlyList<int> Foregrounds = new[]
|
||||
{
|
||||
BrightWhite,
|
||||
DarkBlack,
|
||||
BrightBlack,
|
||||
DarkRed,
|
||||
BrightRed,
|
||||
DarkGreen,
|
||||
BrightGreen,
|
||||
DarkYellow,
|
||||
BrightYellow,
|
||||
DarkBlue,
|
||||
BrightBlue,
|
||||
DarkMagenta,
|
||||
BrightMagenta,
|
||||
DarkCyan,
|
||||
BrightCyan,
|
||||
DarkWhite,
|
||||
BrightWhite
|
||||
};
|
||||
|
||||
private static readonly IReadOnlyList<int> Backgrounds = new[]
|
||||
{
|
||||
DarkBlack,
|
||||
DarkRed,
|
||||
DarkGreen,
|
||||
DarkYellow,
|
||||
DarkBlue,
|
||||
DarkMagenta,
|
||||
DarkCyan,
|
||||
DarkWhite
|
||||
};
|
||||
|
||||
private const string TestText = " gYw ";
|
||||
|
||||
private static readonly IReadOnlyList<string> AnsiForegroundSequences = new[]
|
||||
{
|
||||
"m",
|
||||
"1m",
|
||||
"30m",
|
||||
"1;30m",
|
||||
"31m",
|
||||
"1;31m",
|
||||
"32m",
|
||||
"1;32m",
|
||||
"33m",
|
||||
"1;33m",
|
||||
"34m",
|
||||
"1;34m",
|
||||
"35m",
|
||||
"1;35m",
|
||||
"36m",
|
||||
"1;36m",
|
||||
"37m",
|
||||
"1;37m"
|
||||
};
|
||||
|
||||
private static readonly IReadOnlyList<string> AnsiBackgroundSequences = new[]
|
||||
{
|
||||
"m",
|
||||
"40m",
|
||||
"41m",
|
||||
"42m",
|
||||
"43m",
|
||||
"44m",
|
||||
"45m",
|
||||
"46m",
|
||||
"47m"
|
||||
};
|
||||
|
||||
public static void PrintTable()
|
||||
{
|
||||
ConsoleColor[] colors = (ConsoleColor[])ConsoleColor.GetValues(typeof(ConsoleColor));
|
||||
// Save the current background and foreground colors.
|
||||
ConsoleColor currentBackground = Console.BackgroundColor;
|
||||
ConsoleColor currentForeground = Console.ForegroundColor;
|
||||
|
||||
Console.Write("\t");
|
||||
for (int bg = 0; bg < AnsiBackgroundSequences.Count; bg++)
|
||||
{
|
||||
if (bg > 0) Console.Write(" ");
|
||||
Console.Write(" ");
|
||||
Console.Write(bg == 0 ? " " : AnsiBackgroundSequences[bg]);
|
||||
Console.Write(" ");
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
for (int fg = 0; fg < AnsiForegroundSequences.Count; fg++)
|
||||
{
|
||||
Console.ForegroundColor = currentForeground;
|
||||
Console.BackgroundColor = currentBackground;
|
||||
|
||||
if (fg >= 0) Console.Write(AnsiForegroundSequences[fg] + "\t");
|
||||
|
||||
if (fg == 0) Console.ForegroundColor = currentForeground;
|
||||
else Console.ForegroundColor = colors[Foregrounds[fg - 1]];
|
||||
|
||||
for (int bg = 0; bg < AnsiBackgroundSequences.Count; bg++)
|
||||
{
|
||||
if (bg > 0) Console.Write(" ");
|
||||
if (bg == 0)
|
||||
Console.BackgroundColor = currentBackground;
|
||||
else Console.BackgroundColor = colors[Backgrounds[bg - 1]];
|
||||
Console.Write(TestText);
|
||||
Console.BackgroundColor = currentBackground;
|
||||
}
|
||||
Console.Write("\n");
|
||||
}
|
||||
Console.Write("\n");
|
||||
|
||||
// Reset foreground and background colors
|
||||
Console.ForegroundColor = currentForeground;
|
||||
Console.BackgroundColor = currentBackground;
|
||||
}
|
||||
|
||||
public static void PrintTableWithVt()
|
||||
{
|
||||
Console.Write("\t");
|
||||
for (int bg = 0; bg < AnsiBackgroundSequences.Count; bg++)
|
||||
{
|
||||
if (bg > 0) Console.Write(" ");
|
||||
Console.Write(" ");
|
||||
Console.Write(bg == 0 ? " " : AnsiBackgroundSequences[bg]);
|
||||
Console.Write(" ");
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
for (int fg = 0; fg < AnsiForegroundSequences.Count; fg++)
|
||||
{
|
||||
Console.Write("\x1b[m");
|
||||
|
||||
if (fg >= 0)
|
||||
{
|
||||
Console.Write(AnsiForegroundSequences[fg] + "\t");
|
||||
}
|
||||
|
||||
if (fg == 0)
|
||||
{
|
||||
Console.Write("\x1b[39m");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write("\x1b[" + AnsiForegroundSequences[fg]);
|
||||
}
|
||||
|
||||
for (int bg = 0; bg < AnsiBackgroundSequences.Count; bg++)
|
||||
{
|
||||
if (bg > 0)
|
||||
{
|
||||
Console.Write(" ");
|
||||
}
|
||||
if (bg == 0)
|
||||
{
|
||||
Console.Write("\x1b[49m");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write("\x1b[" + AnsiBackgroundSequences[bg]);
|
||||
}
|
||||
|
||||
Console.Write(TestText);
|
||||
Console.Write("\x1b[49m");
|
||||
}
|
||||
Console.Write("\n");
|
||||
}
|
||||
Console.Write("\n");
|
||||
|
||||
// Reset foreground and background colors
|
||||
Console.Write("\x1b[m");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net46</TargetFramework>
|
||||
<TargetFramework>net461</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
|
@ -8,9 +8,11 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace ColorTool
|
||||
{
|
||||
class ConsoleAPI
|
||||
static class ConsoleAPI
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
private const int StdOutputHandle = -11;
|
||||
public const int ColorTableSize = 16;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct COORD
|
||||
{
|
||||
|
@ -58,7 +60,7 @@ namespace ColorTool
|
|||
}
|
||||
}
|
||||
|
||||
public static int STD_OUTPUT_HANDLE = -11;
|
||||
public static IntPtr GetStdOutputHandle() => GetStdHandle(StdOutputHandle);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr GetStdHandle(int nStdHandle);
|
||||
|
@ -83,13 +85,10 @@ namespace ColorTool
|
|||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static uint RGB(int r, int g, int b)
|
||||
{
|
||||
return (uint)r + (((uint)g) << 8) + (((uint)b) << 16);
|
||||
}
|
||||
|
||||
public const int COLOR_TABLE_SIZE = 16;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,26 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
namespace ColorTool
|
||||
{
|
||||
public struct ConsoleAttributes
|
||||
/// <summary>
|
||||
/// Keeps track of the color table indices for the background/foreground in a colorscheme.
|
||||
/// </summary>
|
||||
public readonly struct ConsoleAttributes
|
||||
{
|
||||
public uint? foreground;
|
||||
public uint? background;
|
||||
|
||||
public uint? popupForeground;
|
||||
public uint? popupBackground;
|
||||
public ConsoleAttributes(uint? background, uint? foreground, uint? popupBackground, uint? popupForeground)
|
||||
{
|
||||
Background = background;
|
||||
Foreground = foreground;
|
||||
PopupBackground = popupBackground;
|
||||
PopupForeground = popupForeground;
|
||||
}
|
||||
|
||||
public uint? Foreground { get; }
|
||||
public uint? Background { get; }
|
||||
public uint? PopupForeground { get; }
|
||||
public uint? PopupBackground { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
using System;
|
||||
using static ColorTool.ConsoleAPI;
|
||||
|
||||
namespace ColorTool.ConsoleTargets
|
||||
{
|
||||
/// <summary>
|
||||
/// A console target that writes to the currently open console.
|
||||
/// </summary>
|
||||
class CurrentConsoleTarget : IConsoleTarget
|
||||
{
|
||||
public void ApplyColorScheme(ColorScheme colorScheme, bool quietMode)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO_EX csbiex = CONSOLE_SCREEN_BUFFER_INFO_EX.Create();
|
||||
IntPtr hOut = GetStdOutputHandle();
|
||||
bool success = GetConsoleScreenBufferInfoEx(hOut, ref csbiex);
|
||||
if (!success)
|
||||
{
|
||||
throw new InvalidOperationException("Could not obtain console screen buffer");
|
||||
}
|
||||
|
||||
csbiex.srWindow.Bottom++;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
csbiex.ColorTable[i] = colorScheme.ColorTable[i];
|
||||
}
|
||||
if(colorScheme.ScreenColorAttributes is ushort wAttrs)
|
||||
{
|
||||
csbiex.wAttributes = wAttrs;
|
||||
}
|
||||
if(colorScheme.PopupColorAttributes is ushort wPopupAttrs)
|
||||
{
|
||||
csbiex.wPopupAttributes = wPopupAttrs;
|
||||
}
|
||||
SetConsoleScreenBufferInfoEx(hOut, ref csbiex);
|
||||
|
||||
if (!quietMode)
|
||||
{
|
||||
ColorTable.PrintTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
|
||||
namespace ColorTool.ConsoleTargets
|
||||
{
|
||||
/// <summary>
|
||||
/// A console target that writes to the Windows registry to modify system defaults
|
||||
/// </summary>
|
||||
class DefaultConsoleTarget : IConsoleTarget
|
||||
{
|
||||
public void ApplyColorScheme(ColorScheme colorScheme, bool quietMode)
|
||||
{
|
||||
RegistryKey consoleKey = Registry.CurrentUser.OpenSubKey("Console", true);
|
||||
for (int i = 0; i < colorScheme.ColorTable.Length; i++)
|
||||
{
|
||||
string valueName = "ColorTable" + (i < 10 ? "0" : "") + i;
|
||||
consoleKey.SetValue(valueName, colorScheme.ColorTable[i], RegistryValueKind.DWord);
|
||||
}
|
||||
if(colorScheme.ScreenColorAttributes is ushort screenColors)
|
||||
{
|
||||
consoleKey.SetValue("ScreenColors", screenColors, RegistryValueKind.DWord);
|
||||
}
|
||||
if(colorScheme.PopupColorAttributes is ushort popupColors)
|
||||
{
|
||||
consoleKey.SetValue("PopupColors", popupColors, RegistryValueKind.DWord);
|
||||
}
|
||||
|
||||
Console.WriteLine(Resources.WroteToDefaults);
|
||||
}
|
||||
}
|
||||
}
|
15
tools/ColorTool/ColorTool/ConsoleTargets/IConsoleTarget.cs
Normal file
15
tools/ColorTool/ColorTool/ConsoleTargets/IConsoleTarget.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
namespace ColorTool.ConsoleTargets
|
||||
{
|
||||
/// <summary>
|
||||
/// A console that can have a color scheme applied to it.
|
||||
/// </summary>
|
||||
interface IConsoleTarget
|
||||
{
|
||||
void ApplyColorScheme(ColorScheme colorScheme, bool quietMode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using static ColorTool.ConsoleAPI;
|
||||
|
||||
namespace ColorTool.ConsoleTargets
|
||||
{
|
||||
/// <summary>
|
||||
/// A console target that writes to the currently open console, using VT sequences.
|
||||
/// </summary>
|
||||
class VirtualTerminalConsoleTarget : IConsoleTarget
|
||||
{
|
||||
// Use a Console index in to get a VT index out.
|
||||
public static readonly IReadOnlyList<int> VirtualTerminalIndices = new[]
|
||||
{
|
||||
0, // Dark Black
|
||||
4, // Dark Blue
|
||||
2, // Dark Green
|
||||
6, // Dark Cyan
|
||||
1, // Dark Red
|
||||
5, // Dark Magenta
|
||||
3, // Dark Yellow
|
||||
7, // Dark White
|
||||
8+0, // Bright Black
|
||||
8+4, // Bright Blue
|
||||
8+2, // Bright Green
|
||||
8+6, // Bright Cyan
|
||||
8+1, // Bright Red
|
||||
8+5, // Bright Magenta
|
||||
8+3, // Bright Yellow
|
||||
8+7, // Bright White
|
||||
};
|
||||
|
||||
public void ApplyColorScheme(ColorScheme colorScheme, bool quietMode)
|
||||
{
|
||||
IntPtr hOut = GetStdOutputHandle();
|
||||
uint originalMode;
|
||||
uint requestedMode;
|
||||
bool succeeded = GetConsoleMode(hOut, out originalMode);
|
||||
if (succeeded)
|
||||
{
|
||||
requestedMode = originalMode | (uint)ConsoleAPI.ConsoleOutputModes.ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
SetConsoleMode(hOut, requestedMode);
|
||||
}
|
||||
|
||||
for (int i = 0; i < colorScheme.ColorTable.Length; i++)
|
||||
{
|
||||
int vtIndex = VirtualTerminalIndices[i];
|
||||
Color color = colorScheme[i];
|
||||
string s = $"\x1b]4;{vtIndex};rgb:{color.R:X}/{color.G:X}/{color.B:X}\x7";
|
||||
Console.Write(s);
|
||||
}
|
||||
if (!quietMode)
|
||||
{
|
||||
ColorTable.PrintTableWithVt();
|
||||
}
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
SetConsoleMode(hOut, originalMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,497 +1,25 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
using Microsoft.Win32;
|
||||
using ColorTool.ConsoleTargets;
|
||||
using ColorTool.SchemeWriters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using static ColorTool.ConsoleAPI;
|
||||
|
||||
namespace ColorTool
|
||||
{
|
||||
class Program
|
||||
static class Program
|
||||
{
|
||||
static int DARK_BLACK = 0;
|
||||
static int DARK_BLUE = 1;
|
||||
static int DARK_GREEN = 2;
|
||||
static int DARK_CYAN = 3;
|
||||
static int DARK_RED = 4;
|
||||
static int DARK_MAGENTA = 5;
|
||||
static int DARK_YELLOW = 6;
|
||||
static int DARK_WHITE = 7;
|
||||
static int BRIGHT_BLACK = 8;
|
||||
static int BRIGHT_BLUE = 9;
|
||||
static int BRIGHT_GREEN = 10;
|
||||
static int BRIGHT_CYAN = 11;
|
||||
static int BRIGHT_RED = 12;
|
||||
static int BRIGHT_MAGENTA = 13;
|
||||
static int BRIGHT_YELLOW = 14;
|
||||
static int BRIGHT_WHITE = 15;
|
||||
private static bool quietMode = false;
|
||||
private static bool reportErrors = false;
|
||||
private static bool setDefaults = false;
|
||||
private static bool setProperties = true;
|
||||
private static bool setUnixStyle = false;
|
||||
|
||||
static int[] saneFgs = {
|
||||
DARK_BLACK ,
|
||||
DARK_RED ,
|
||||
DARK_GREEN ,
|
||||
DARK_YELLOW ,
|
||||
DARK_BLUE ,
|
||||
DARK_MAGENTA ,
|
||||
DARK_CYAN ,
|
||||
DARK_WHITE ,
|
||||
BRIGHT_BLACK ,
|
||||
BRIGHT_RED ,
|
||||
BRIGHT_GREEN ,
|
||||
BRIGHT_YELLOW ,
|
||||
BRIGHT_MAGENTA ,
|
||||
BRIGHT_BLUE ,
|
||||
BRIGHT_CYAN ,
|
||||
BRIGHT_WHITE
|
||||
};
|
||||
|
||||
// This is the order of colors when output by the table.
|
||||
static int[] outputFgs = {
|
||||
BRIGHT_WHITE ,
|
||||
DARK_BLACK ,
|
||||
BRIGHT_BLACK ,
|
||||
DARK_RED ,
|
||||
BRIGHT_RED ,
|
||||
DARK_GREEN ,
|
||||
BRIGHT_GREEN ,
|
||||
DARK_YELLOW ,
|
||||
BRIGHT_YELLOW ,
|
||||
DARK_BLUE ,
|
||||
BRIGHT_BLUE ,
|
||||
DARK_MAGENTA ,
|
||||
BRIGHT_MAGENTA ,
|
||||
DARK_CYAN ,
|
||||
BRIGHT_CYAN ,
|
||||
DARK_WHITE ,
|
||||
BRIGHT_WHITE
|
||||
};
|
||||
|
||||
static int[] saneBgs = {
|
||||
DARK_BLACK ,
|
||||
DARK_RED ,
|
||||
DARK_GREEN ,
|
||||
DARK_YELLOW ,
|
||||
DARK_BLUE ,
|
||||
DARK_MAGENTA ,
|
||||
DARK_CYAN ,
|
||||
DARK_WHITE
|
||||
};
|
||||
|
||||
// Use a Console index in to get a VT index out.
|
||||
static int[] VT_INDICIES = {
|
||||
0, // DARK_BLACK
|
||||
4, // DARK_BLUE
|
||||
2, // DARK_GREEN
|
||||
6, // DARK_CYAN
|
||||
1, // DARK_RED
|
||||
5, // DARK_MAGENTA
|
||||
3, // DARK_YELLOW
|
||||
7, // DARK_WHITE
|
||||
8+0, // BRIGHT_BLACK
|
||||
8+4, // BRIGHT_BLUE
|
||||
8+2, // BRIGHT_GREEN
|
||||
8+6, // BRIGHT_CYAN
|
||||
8+1, // BRIGHT_RED
|
||||
8+5, // BRIGHT_MAGENTA
|
||||
8+3, // BRIGHT_YELLOW
|
||||
8+7,// BRIGHT_WHITE
|
||||
};
|
||||
|
||||
static bool quietMode = false;
|
||||
static bool reportErrors = false;
|
||||
static bool setDefaults = false;
|
||||
static bool setProperties = true;
|
||||
static bool setUnixStyle = false;
|
||||
|
||||
static void Usage()
|
||||
{
|
||||
Console.WriteLine(Resources.Usage,
|
||||
string.Join($"{Environment.NewLine} ", GetParsers().Select(p => p.Name)));
|
||||
}
|
||||
|
||||
static void OutputUsage()
|
||||
{
|
||||
Console.WriteLine(Resources.OutputUsage);
|
||||
}
|
||||
|
||||
static void Version()
|
||||
{
|
||||
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
|
||||
var info = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location);
|
||||
Console.WriteLine($"colortool v{info.FileVersion}");
|
||||
}
|
||||
|
||||
static void PrintTable()
|
||||
{
|
||||
ConsoleColor[] colors = (ConsoleColor[])ConsoleColor.GetValues(typeof(ConsoleColor));
|
||||
// Save the current background and foreground colors.
|
||||
ConsoleColor currentBackground = Console.BackgroundColor;
|
||||
ConsoleColor currentForeground = Console.ForegroundColor;
|
||||
string test = " gYw ";
|
||||
string[] FGs = {
|
||||
"m",
|
||||
"1m",
|
||||
"30m",
|
||||
"1;30m",
|
||||
"31m",
|
||||
"1;31m",
|
||||
"32m",
|
||||
"1;32m",
|
||||
"33m",
|
||||
"1;33m",
|
||||
"34m",
|
||||
"1;34m",
|
||||
"35m",
|
||||
"1;35m",
|
||||
"36m",
|
||||
"1;36m",
|
||||
"37m",
|
||||
"1;37m"
|
||||
};
|
||||
string[] BGs = {
|
||||
"m",
|
||||
"40m",
|
||||
"41m",
|
||||
"42m",
|
||||
"43m",
|
||||
"44m",
|
||||
"45m",
|
||||
"46m",
|
||||
"47m"
|
||||
};
|
||||
|
||||
Console.Write("\t");
|
||||
for (int bg = 0; bg < BGs.Length; bg++)
|
||||
{
|
||||
if (bg > 0) Console.Write(" ");
|
||||
Console.Write(" ");
|
||||
Console.Write(bg == 0 ? " " : BGs[bg]);
|
||||
Console.Write(" ");
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
for (int fg = 0; fg < FGs.Length; fg++)
|
||||
{
|
||||
Console.ForegroundColor = currentForeground;
|
||||
Console.BackgroundColor = currentBackground;
|
||||
|
||||
if (fg >= 0) Console.Write(FGs[fg] + "\t");
|
||||
|
||||
if (fg == 0) Console.ForegroundColor = currentForeground;
|
||||
else Console.ForegroundColor = colors[outputFgs[fg - 1]];
|
||||
|
||||
for (int bg = 0; bg < BGs.Length; bg++)
|
||||
{
|
||||
if (bg > 0) Console.Write(" ");
|
||||
if (bg == 0)
|
||||
Console.BackgroundColor = currentBackground;
|
||||
else Console.BackgroundColor = colors[saneBgs[bg - 1]];
|
||||
Console.Write(test);
|
||||
Console.BackgroundColor = currentBackground;
|
||||
}
|
||||
Console.Write("\n");
|
||||
|
||||
}
|
||||
Console.Write("\n");
|
||||
|
||||
// Reset foreground and background colors
|
||||
Console.ForegroundColor = currentForeground;
|
||||
Console.BackgroundColor = currentBackground;
|
||||
}
|
||||
|
||||
static void PrintTableWithVt()
|
||||
{
|
||||
// Save the current background and foreground colors.
|
||||
string test = " gYw ";
|
||||
string[] FGs = {
|
||||
"m",
|
||||
"1m",
|
||||
"30m",
|
||||
"1;30m",
|
||||
"31m",
|
||||
"1;31m",
|
||||
"32m",
|
||||
"1;32m",
|
||||
"33m",
|
||||
"1;33m",
|
||||
"34m",
|
||||
"1;34m",
|
||||
"35m",
|
||||
"1;35m",
|
||||
"36m",
|
||||
"1;36m",
|
||||
"37m",
|
||||
"1;37m"
|
||||
};
|
||||
string[] BGs = {
|
||||
"m",
|
||||
"40m",
|
||||
"41m",
|
||||
"42m",
|
||||
"43m",
|
||||
"44m",
|
||||
"45m",
|
||||
"46m",
|
||||
"47m"
|
||||
};
|
||||
|
||||
Console.Write("\t");
|
||||
for (int bg = 0; bg < BGs.Length; bg++)
|
||||
{
|
||||
if (bg > 0) Console.Write(" ");
|
||||
Console.Write(" ");
|
||||
Console.Write(bg == 0 ? " " : BGs[bg]);
|
||||
Console.Write(" ");
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
for (int fg = 0; fg < FGs.Length; fg++)
|
||||
{
|
||||
Console.Write("\x1b[m");
|
||||
|
||||
if (fg >= 0)
|
||||
{
|
||||
Console.Write(FGs[fg] + "\t");
|
||||
}
|
||||
|
||||
if (fg == 0)
|
||||
{
|
||||
Console.Write("\x1b[39m");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write("\x1b[" + FGs[fg]);
|
||||
}
|
||||
|
||||
for (int bg = 0; bg < BGs.Length; bg++)
|
||||
{
|
||||
if (bg > 0)
|
||||
{
|
||||
Console.Write(" ");
|
||||
}
|
||||
if (bg == 0)
|
||||
{
|
||||
Console.Write("\x1b[49m");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write("\x1b[" + BGs[bg]);
|
||||
}
|
||||
|
||||
Console.Write(test);
|
||||
Console.Write("\x1b[49m");
|
||||
}
|
||||
Console.Write("\n");
|
||||
|
||||
}
|
||||
Console.Write("\n");
|
||||
|
||||
// Reset foreground and background colors
|
||||
Console.Write("\x1b[m");
|
||||
}
|
||||
|
||||
private static IntPtr GetStdOutputHandle()
|
||||
{
|
||||
return GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
}
|
||||
|
||||
static void PrintSchemes()
|
||||
{
|
||||
var schemeDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "schemes");
|
||||
|
||||
if (Directory.Exists(schemeDirectory))
|
||||
{
|
||||
IntPtr handle = GetStdOutputHandle();
|
||||
GetConsoleMode(handle, out var mode);
|
||||
SetConsoleMode(handle, mode | 0x4);
|
||||
|
||||
int consoleWidth = Console.WindowWidth;
|
||||
string fgText = " gYw ";
|
||||
foreach (string schemeName in Directory.GetFiles(schemeDirectory).Select(Path.GetFileName))
|
||||
{
|
||||
ColorScheme colorScheme = GetScheme(schemeName, false);
|
||||
if (colorScheme != null)
|
||||
{
|
||||
string colors = string.Empty;
|
||||
for (var index = 0; index < 8; index++)
|
||||
{
|
||||
uint t = colorScheme.colorTable[index];
|
||||
var color = UIntToColor(t);
|
||||
// Set the background color to the color in the scheme, plus some text to show how it looks
|
||||
colors += $"\x1b[48;2;{color.R};{color.G};{color.B}m{fgText}";
|
||||
}
|
||||
// Align scheme colors right, or on newline if it doesn't fit
|
||||
int schemeTextLength = fgText.Length * 8;
|
||||
int bufferLength = consoleWidth - (schemeName.Length + schemeTextLength);
|
||||
|
||||
string bufferString = bufferLength >= 0
|
||||
? new string(' ', bufferLength)
|
||||
: "\n" + new string(' ', consoleWidth - schemeTextLength);
|
||||
|
||||
string outputString = schemeName + bufferString + colors;
|
||||
Console.WriteLine(outputString);
|
||||
Console.ResetColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintSchemesDirectory()
|
||||
{
|
||||
string schemeDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "schemes");
|
||||
Console.WriteLine(schemeDirectory);
|
||||
}
|
||||
|
||||
private static Color UIntToColor(uint color)
|
||||
{
|
||||
byte r = (byte)(color >> 0);
|
||||
byte g = (byte)(color >> 8);
|
||||
byte b = (byte)(color >> 16);
|
||||
return Color.FromArgb(r, g, b);
|
||||
}
|
||||
|
||||
static bool SetProperties(ColorScheme colorScheme)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO_EX csbiex = CONSOLE_SCREEN_BUFFER_INFO_EX.Create();
|
||||
IntPtr hOut = GetStdOutputHandle();
|
||||
bool success = GetConsoleScreenBufferInfoEx(hOut, ref csbiex);
|
||||
if (success)
|
||||
{
|
||||
csbiex.srWindow.Bottom++;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
csbiex.ColorTable[i] = colorScheme.colorTable[i];
|
||||
}
|
||||
if (colorScheme.consoleAttributes.background != null && colorScheme.consoleAttributes.foreground != null)
|
||||
{
|
||||
int fgidx = colorScheme.CalculateIndex(colorScheme.consoleAttributes.foreground.Value);
|
||||
int bgidx = colorScheme.CalculateIndex(colorScheme.consoleAttributes.background.Value);
|
||||
csbiex.wAttributes = (ushort)(fgidx | (bgidx << 4));
|
||||
}
|
||||
if (colorScheme.consoleAttributes.popupBackground != null && colorScheme.consoleAttributes.popupForeground != null)
|
||||
{
|
||||
int fgidx = colorScheme.CalculateIndex(colorScheme.consoleAttributes.popupForeground.Value);
|
||||
int bgidx = colorScheme.CalculateIndex(colorScheme.consoleAttributes.popupBackground.Value);
|
||||
csbiex.wPopupAttributes = (ushort)(fgidx | (bgidx << 4));
|
||||
}
|
||||
SetConsoleScreenBufferInfoEx(hOut, ref csbiex);
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
if (!quietMode)
|
||||
{
|
||||
PrintTable();
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool SetPropertiesWithVt(ColorScheme colorScheme)
|
||||
{
|
||||
IntPtr hOut = GetStdOutputHandle();
|
||||
uint originalMode;
|
||||
uint requestedMode;
|
||||
bool succeeded = GetConsoleMode(hOut, out originalMode);
|
||||
if (succeeded)
|
||||
{
|
||||
requestedMode = originalMode | (uint)ConsoleAPI.ConsoleOutputModes.ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
SetConsoleMode(hOut, requestedMode);
|
||||
|
||||
}
|
||||
|
||||
for (int i = 0; i < colorScheme.colorTable.Length; i++)
|
||||
{
|
||||
int vtIndex = VT_INDICIES[i];
|
||||
Color color = UIntToColor(colorScheme.colorTable[i]);
|
||||
string s = $"\x1b]4;{vtIndex};rgb:{color.R:X}/{color.G:X}/{color.B:X}\x7";
|
||||
Console.Write(s);
|
||||
}
|
||||
if (!quietMode)
|
||||
{
|
||||
PrintTableWithVt();
|
||||
}
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
SetConsoleMode(hOut, originalMode);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
static bool SetDefaults(ColorScheme colorScheme)
|
||||
{
|
||||
//TODO
|
||||
RegistryKey consoleKey = Registry.CurrentUser.OpenSubKey("Console", true);
|
||||
for (int i = 0; i < colorScheme.colorTable.Length; i++)
|
||||
{
|
||||
string valueName = "ColorTable" + (i < 10 ? "0" : "") + i;
|
||||
consoleKey.SetValue(valueName, colorScheme.colorTable[i], RegistryValueKind.DWord);
|
||||
}
|
||||
Console.WriteLine(Resources.WroteToDefaults);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ExportCurrentAsIni(string outputPath)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO_EX csbiex = CONSOLE_SCREEN_BUFFER_INFO_EX.Create();
|
||||
IntPtr hOut = GetStdOutputHandle();
|
||||
bool success = GetConsoleScreenBufferInfoEx(hOut, ref csbiex);
|
||||
if (success)
|
||||
{
|
||||
try
|
||||
{
|
||||
// StreamWriter can fail for a variety of file system reasons so catch exceptions and print message.
|
||||
using (System.IO.StreamWriter file = new System.IO.StreamWriter(outputPath))
|
||||
{
|
||||
file.WriteLine("[table]");
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
string line = IniSchemeParser.COLOR_NAMES[i];
|
||||
line += " = ";
|
||||
uint color = csbiex.ColorTable[i];
|
||||
uint r = color & (0x000000ff);
|
||||
uint g = (color & (0x0000ff00)) >> 8;
|
||||
uint b = (color & (0x00ff0000)) >> 16;
|
||||
line += r + "," + g + "," + b;
|
||||
file.WriteLine(line);
|
||||
}
|
||||
|
||||
file.WriteLine();
|
||||
file.WriteLine("[screen]");
|
||||
var forgroundIndex = csbiex.wAttributes & 0xF;
|
||||
var backgroundIndex = csbiex.wAttributes >> 4;
|
||||
file.WriteLine($"FOREGROUND = {IniSchemeParser.COLOR_NAMES[forgroundIndex]}");
|
||||
file.WriteLine($"BACKGROUND = {IniSchemeParser.COLOR_NAMES[backgroundIndex]}");
|
||||
|
||||
file.WriteLine();
|
||||
file.WriteLine("[popup]");
|
||||
forgroundIndex = csbiex.wPopupAttributes & 0xF;
|
||||
backgroundIndex = csbiex.wPopupAttributes >> 4;
|
||||
file.WriteLine($"FOREGROUND = {IniSchemeParser.COLOR_NAMES[forgroundIndex]}");
|
||||
file.WriteLine($"BACKGROUND = {IniSchemeParser.COLOR_NAMES[backgroundIndex]}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Failed to get console information.");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
{
|
||||
|
@ -505,7 +33,7 @@ namespace ColorTool
|
|||
{
|
||||
case "-c":
|
||||
case "--current":
|
||||
PrintTable();
|
||||
ColorTable.PrintTable();
|
||||
return;
|
||||
case "-e":
|
||||
case "--errors":
|
||||
|
@ -535,7 +63,7 @@ namespace ColorTool
|
|||
return;
|
||||
case "-l":
|
||||
case "--location":
|
||||
PrintSchemesDirectory();
|
||||
SchemeManager.PrintSchemesDirectory();
|
||||
return;
|
||||
case "-x":
|
||||
case "--xterm":
|
||||
|
@ -546,7 +74,7 @@ namespace ColorTool
|
|||
case "--output":
|
||||
if (i + 1 < args.Length)
|
||||
{
|
||||
ExportCurrentAsIni(args[i + 1]);
|
||||
new IniSchemeWriter().ExportCurrentAsIni(args[i + 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -555,7 +83,7 @@ namespace ColorTool
|
|||
return;
|
||||
case "-s":
|
||||
case "--schemes":
|
||||
PrintSchemes();
|
||||
SchemeManager.PrintSchemes();
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
|
@ -564,7 +92,7 @@ namespace ColorTool
|
|||
|
||||
string schemeName = args[args.Length - 1];
|
||||
|
||||
ColorScheme colorScheme = GetScheme(schemeName, reportErrors);
|
||||
ColorScheme colorScheme = SchemeManager.GetScheme(schemeName, reportErrors);
|
||||
|
||||
if (colorScheme == null)
|
||||
{
|
||||
|
@ -572,41 +100,51 @@ namespace ColorTool
|
|||
return;
|
||||
}
|
||||
|
||||
foreach (var target in GetConsoleTargets())
|
||||
{
|
||||
target.ApplyColorScheme(colorScheme, quietMode);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Usage()
|
||||
{
|
||||
Console.WriteLine(Resources.Usage,
|
||||
string.Join($"{Environment.NewLine} ", SchemeManager.GetParsers().Select(p => p.Name)));
|
||||
}
|
||||
|
||||
private static void OutputUsage()
|
||||
{
|
||||
Console.WriteLine(Resources.OutputUsage);
|
||||
}
|
||||
|
||||
private static void Version()
|
||||
{
|
||||
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
|
||||
var info = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location);
|
||||
Console.WriteLine($"colortool v{info.FileVersion}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerable of consoles that we want to apply the colorscheme to.
|
||||
/// The contents of this enumerable depends on the user's provided command line flags.
|
||||
/// </summary>
|
||||
private static IEnumerable<IConsoleTarget> GetConsoleTargets()
|
||||
{
|
||||
if (setDefaults)
|
||||
{
|
||||
SetDefaults(colorScheme);
|
||||
yield return new DefaultConsoleTarget();
|
||||
}
|
||||
if (setProperties)
|
||||
{
|
||||
if (setUnixStyle)
|
||||
{
|
||||
SetPropertiesWithVt(colorScheme);
|
||||
yield return new VirtualTerminalConsoleTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetProperties(colorScheme);
|
||||
yield return new CurrentConsoleTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ISchemeParser> GetParsers()
|
||||
{
|
||||
return typeof(Program).Assembly.GetTypes()
|
||||
.Where(t => !t.IsAbstract && typeof(ISchemeParser).IsAssignableFrom(t))
|
||||
.Select(t => (ISchemeParser)Activator.CreateInstance(t));
|
||||
}
|
||||
|
||||
private static ColorScheme GetScheme(string schemeName, bool reportErrors = false)
|
||||
{
|
||||
foreach (var parser in GetParsers())
|
||||
{
|
||||
ColorScheme scheme = parser.ParseScheme(schemeName, reportErrors);
|
||||
if (scheme != null)
|
||||
{
|
||||
return scheme;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace ColorTool
|
||||
{
|
||||
static class Scheme
|
||||
{
|
||||
public static IEnumerable<string> GetSearchPaths(string schemeName, string extension)
|
||||
{
|
||||
// Search order, for argument "name", where 'exe' is the dir of the exe.
|
||||
// 1. ./name
|
||||
// 2. ./name.ext
|
||||
// 3. ./schemes/name
|
||||
// 4. ./schemes/name.ext
|
||||
// 5. exe/schemes/name
|
||||
// 6. exe/schemes/name.ext
|
||||
// 7. name (as an absolute path)
|
||||
|
||||
string cwd = "./";
|
||||
yield return cwd + schemeName;
|
||||
|
||||
string filename = schemeName + extension;
|
||||
yield return cwd + filename;
|
||||
|
||||
string cwdSchemes = "./schemes/";
|
||||
yield return cwdSchemes + schemeName;
|
||||
yield return cwdSchemes + filename;
|
||||
|
||||
string exeDir = Directory.GetParent(System.Reflection.Assembly.GetEntryAssembly().Location).FullName;
|
||||
string exeSchemes = exeDir + "/schemes/";
|
||||
yield return exeSchemes + schemeName;
|
||||
yield return exeSchemes + filename;
|
||||
yield return schemeName;
|
||||
}
|
||||
}
|
||||
}
|
106
tools/ColorTool/ColorTool/SchemeManager.cs
Normal file
106
tools/ColorTool/ColorTool/SchemeManager.cs
Normal file
|
@ -0,0 +1,106 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
using ColorTool.SchemeParsers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using static ColorTool.ConsoleAPI;
|
||||
|
||||
namespace ColorTool
|
||||
{
|
||||
static class SchemeManager
|
||||
{
|
||||
public static IEnumerable<string> GetSearchPaths(string schemeName, string extension)
|
||||
{
|
||||
// Search order, for argument "name", where 'exe' is the dir of the exe.
|
||||
// 1. ./name
|
||||
// 2. ./name.ext
|
||||
// 3. ./schemes/name
|
||||
// 4. ./schemes/name.ext
|
||||
// 5. exe/schemes/name
|
||||
// 6. exe/schemes/name.ext
|
||||
// 7. name (as an absolute path)
|
||||
|
||||
string cwd = "./";
|
||||
yield return cwd + schemeName;
|
||||
|
||||
string filename = schemeName + extension;
|
||||
yield return cwd + filename;
|
||||
|
||||
string cwdSchemes = "./schemes/";
|
||||
yield return cwdSchemes + schemeName;
|
||||
yield return cwdSchemes + filename;
|
||||
|
||||
string exeDir = Directory.GetParent(System.Reflection.Assembly.GetEntryAssembly().Location).FullName;
|
||||
string exeSchemes = exeDir + "/schemes/";
|
||||
yield return exeSchemes + schemeName;
|
||||
yield return exeSchemes + filename;
|
||||
yield return schemeName;
|
||||
}
|
||||
|
||||
public static void PrintSchemesDirectory()
|
||||
{
|
||||
string schemeDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "schemes");
|
||||
Console.WriteLine(schemeDirectory);
|
||||
}
|
||||
|
||||
public static void PrintSchemes()
|
||||
{
|
||||
var schemeDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "schemes");
|
||||
|
||||
if (Directory.Exists(schemeDirectory))
|
||||
{
|
||||
IntPtr handle = GetStdOutputHandle();
|
||||
GetConsoleMode(handle, out var mode);
|
||||
SetConsoleMode(handle, mode | 0x4);
|
||||
|
||||
int consoleWidth = Console.WindowWidth;
|
||||
string fgText = " gYw ";
|
||||
foreach (string schemeName in Directory.GetFiles(schemeDirectory).Select(Path.GetFileName))
|
||||
{
|
||||
ColorScheme colorScheme = GetScheme(schemeName, false);
|
||||
if (colorScheme != null)
|
||||
{
|
||||
string colors = string.Empty;
|
||||
for (var index = 0; index < 8; index++)
|
||||
{
|
||||
var color = colorScheme[index];
|
||||
// Set the background color to the color in the scheme, plus some text to show how it looks
|
||||
colors += $"\x1b[48;2;{color.R};{color.G};{color.B}m{fgText}";
|
||||
}
|
||||
// Align scheme colors right, or on newline if it doesn't fit
|
||||
int schemeTextLength = fgText.Length * 8;
|
||||
int bufferLength = consoleWidth - (schemeName.Length + schemeTextLength);
|
||||
|
||||
string bufferString = bufferLength >= 0
|
||||
? new string(' ', bufferLength)
|
||||
: "\n" + new string(' ', consoleWidth - schemeTextLength);
|
||||
|
||||
string outputString = schemeName + bufferString + colors;
|
||||
Console.WriteLine(outputString);
|
||||
Console.ResetColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ColorScheme GetScheme(string schemeName, bool reportErrors = false)
|
||||
{
|
||||
return GetParsers()
|
||||
.Where(parser => parser.CanParse(schemeName))
|
||||
.Select(parser => parser.ParseScheme(schemeName, reportErrors))
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public static IEnumerable<ISchemeParser> GetParsers()
|
||||
{
|
||||
return typeof(Program).Assembly.GetTypes()
|
||||
.Where(t => !t.IsAbstract && typeof(ISchemeParser).IsAssignableFrom(t))
|
||||
.Select(t => (ISchemeParser)Activator.CreateInstance(t));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
namespace ColorTool
|
||||
namespace ColorTool.SchemeParsers
|
||||
{
|
||||
interface ISchemeParser
|
||||
{
|
||||
string Name { get; }
|
||||
|
||||
bool CanParse(string schemeName);
|
||||
ColorScheme ParseScheme(string schemeName, bool reportErrors = false);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
|
@ -7,19 +7,22 @@ using System;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using static ColorTool.ConsoleAPI;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using static ColorTool.ConsoleAPI;
|
||||
|
||||
namespace ColorTool
|
||||
namespace ColorTool.SchemeParsers
|
||||
{
|
||||
class IniSchemeParser : ISchemeParser
|
||||
{
|
||||
[DllImport("kernel32")]
|
||||
private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
|
||||
|
||||
private const string FileExtension = ".ini";
|
||||
|
||||
// These are in Windows Color table order - BRG, not RGB.
|
||||
public static string[] COLOR_NAMES = {
|
||||
internal static readonly IReadOnlyList<string> ColorNames = new[]
|
||||
{
|
||||
"DARK_BLACK",
|
||||
"DARK_BLUE",
|
||||
"DARK_GREEN",
|
||||
|
@ -38,44 +41,10 @@ namespace ColorTool
|
|||
"BRIGHT_WHITE"
|
||||
};
|
||||
|
||||
public string Name => "INI File Parser";
|
||||
public string Name { get; } = "INI File Parser";
|
||||
|
||||
static uint ParseHex(string arg)
|
||||
{
|
||||
System.Drawing.Color col = System.Drawing.ColorTranslator.FromHtml(arg);
|
||||
return RGB(col.R, col.G, col.B);
|
||||
}
|
||||
|
||||
static uint ParseRgb(string arg)
|
||||
{
|
||||
int[] components = { 0, 0, 0 };
|
||||
string[] args = arg.Split(',');
|
||||
if (args.Length != components.Length) throw new Exception("Invalid color format \"" + arg + "\"");
|
||||
if (args.Length != 3) throw new Exception("Invalid color format \"" + arg + "\"");
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
components[i] = Int32.Parse(args[i]);
|
||||
}
|
||||
|
||||
return RGB(components[0], components[1], components[2]);
|
||||
}
|
||||
|
||||
static uint ParseColor(string arg)
|
||||
{
|
||||
if (arg[0] == '#')
|
||||
{
|
||||
return ParseHex(arg.Substring(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ParseRgb(arg);
|
||||
}
|
||||
}
|
||||
|
||||
static string FindIniScheme(string schemeName)
|
||||
{
|
||||
return Scheme.GetSearchPaths(schemeName, ".ini").FirstOrDefault(File.Exists);
|
||||
}
|
||||
public bool CanParse(string schemeName) =>
|
||||
string.Equals(Path.GetExtension(schemeName), FileExtension, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public ColorScheme ParseScheme(string schemeName, bool reportErrors = false)
|
||||
{
|
||||
|
@ -84,16 +53,16 @@ namespace ColorTool
|
|||
string filename = FindIniScheme(schemeName);
|
||||
if (filename == null) return null;
|
||||
|
||||
string[] tableStrings = new string[COLOR_TABLE_SIZE];
|
||||
string[] tableStrings = new string[ColorTableSize];
|
||||
uint[] colorTable = null;
|
||||
uint? foregroundColor = null;
|
||||
uint? backgroundColor = null;
|
||||
uint? popupForegroundColor = null;
|
||||
uint? popupBackgroundColor = null;
|
||||
|
||||
for (int i = 0; i < COLOR_TABLE_SIZE; i++)
|
||||
for (int i = 0; i < ColorTableSize; i++)
|
||||
{
|
||||
string name = COLOR_NAMES[i];
|
||||
string name = ColorNames[i];
|
||||
StringBuilder buffer = new StringBuilder(512);
|
||||
GetPrivateProfileString("table", name, null, buffer, 512, filename);
|
||||
|
||||
|
@ -113,16 +82,16 @@ namespace ColorTool
|
|||
{
|
||||
try
|
||||
{
|
||||
colorTable = new uint[COLOR_TABLE_SIZE];
|
||||
for (int i = 0; i < COLOR_TABLE_SIZE; i++)
|
||||
colorTable = new uint[ColorTableSize];
|
||||
for (int i = 0; i < ColorTableSize; i++)
|
||||
{
|
||||
colorTable[i] = ParseColor(tableStrings[i]);
|
||||
}
|
||||
|
||||
if (ReadAttributes("popup", out var foreground, out var background))
|
||||
{
|
||||
var foregroundIndex = (COLOR_NAMES as IList<string>).IndexOf(foreground);
|
||||
var backgroundIndex = (COLOR_NAMES as IList<string>).IndexOf(background);
|
||||
var foregroundIndex = (ColorNames as IList<string>).IndexOf(foreground);
|
||||
var backgroundIndex = (ColorNames as IList<string>).IndexOf(background);
|
||||
if (foregroundIndex != -1 && backgroundIndex != -1)
|
||||
{
|
||||
popupForegroundColor = colorTable[foregroundIndex];
|
||||
|
@ -132,8 +101,8 @@ namespace ColorTool
|
|||
|
||||
if (ReadAttributes("screen", out foreground, out background))
|
||||
{
|
||||
var foregroundIndex = (COLOR_NAMES as IList<string>).IndexOf(foreground);
|
||||
var backgroundIndex = (COLOR_NAMES as IList<string>).IndexOf(background);
|
||||
var foregroundIndex = (ColorNames as IList<string>).IndexOf(foreground);
|
||||
var backgroundIndex = (ColorNames as IList<string>).IndexOf(background);
|
||||
if (foregroundIndex != -1 && backgroundIndex != -1)
|
||||
{
|
||||
foregroundColor = colorTable[foregroundIndex];
|
||||
|
@ -154,8 +123,8 @@ namespace ColorTool
|
|||
|
||||
if (colorTable != null)
|
||||
{
|
||||
var consoleAttributes = new ConsoleAttributes { background = backgroundColor, foreground = foregroundColor, popupBackground = popupBackgroundColor, popupForeground = popupForegroundColor };
|
||||
return new ColorScheme { colorTable = colorTable, consoleAttributes = consoleAttributes };
|
||||
var consoleAttributes = new ConsoleAttributes(backgroundColor, foregroundColor, popupBackgroundColor, popupForegroundColor);
|
||||
return new ColorScheme(colorTable, consoleAttributes);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -170,18 +139,55 @@ namespace ColorTool
|
|||
StringBuilder buffer = new StringBuilder(512);
|
||||
GetPrivateProfileString(section, "FOREGROUND", null, buffer, 512, filename);
|
||||
foreground = buffer.ToString();
|
||||
if (!COLOR_NAMES.Contains(foreground))
|
||||
if (!ColorNames.Contains(foreground))
|
||||
return false;
|
||||
|
||||
|
||||
buffer = new StringBuilder(512);
|
||||
GetPrivateProfileString(section, "BACKGROUND", null, buffer, 512, filename);
|
||||
background = buffer.ToString();
|
||||
if (!COLOR_NAMES.Contains(background))
|
||||
if (!ColorNames.Contains(background))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static uint ParseHex(string arg)
|
||||
{
|
||||
System.Drawing.Color col = System.Drawing.ColorTranslator.FromHtml(arg);
|
||||
return RGB(col.R, col.G, col.B);
|
||||
}
|
||||
|
||||
private static uint ParseRgb(string arg)
|
||||
{
|
||||
int[] components = { 0, 0, 0 };
|
||||
string[] args = arg.Split(',');
|
||||
if (args.Length != components.Length) throw new Exception("Invalid color format \"" + arg + "\"");
|
||||
if (args.Length != 3) throw new Exception("Invalid color format \"" + arg + "\"");
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
components[i] = Int32.Parse(args[i]);
|
||||
}
|
||||
|
||||
return RGB(components[0], components[1], components[2]);
|
||||
}
|
||||
|
||||
private static uint ParseColor(string arg)
|
||||
{
|
||||
if (arg[0] == '#')
|
||||
{
|
||||
return ParseHex(arg.Substring(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ParseRgb(arg);
|
||||
}
|
||||
}
|
||||
|
||||
private static string FindIniScheme(string schemeName)
|
||||
{
|
||||
return SchemeManager.GetSearchPaths(schemeName, FileExtension).FirstOrDefault(File.Exists);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,78 +1,59 @@
|
|||
using System;
|
||||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization.Json;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using static ColorTool.ConsoleAPI;
|
||||
|
||||
namespace ColorTool
|
||||
namespace ColorTool.SchemeParsers
|
||||
{
|
||||
class JsonParser : ISchemeParser
|
||||
{
|
||||
static string[] CONCFG_COLOR_NAMES = {
|
||||
"black", // DARK_BLACK
|
||||
"dark_blue", // DARK_BLUE
|
||||
"dark_green", // DARK_GREEN
|
||||
"dark_cyan", // DARK_CYAN
|
||||
"dark_red", // DARK_RED
|
||||
"dark_magenta", // DARK_MAGENTA
|
||||
"dark_yellow", // DARK_YELLOW
|
||||
"gray", // DARK_WHITE
|
||||
"dark_gray", // BRIGHT_BLACK
|
||||
"blue", // BRIGHT_BLUE
|
||||
"green", // BRIGHT_GREEN
|
||||
"cyan", // BRIGHT_CYAN
|
||||
"red", // BRIGHT_RED
|
||||
"magenta", // BRIGHT_MAGENTA
|
||||
"yellow", // BRIGHT_YELLOW
|
||||
"white" // BRIGHT_WHITE
|
||||
private const string FileExtension = ".json";
|
||||
private static readonly IReadOnlyList<string> ConcfgColorNames = new[]
|
||||
{
|
||||
"black", // Dark Black
|
||||
"dark_blue", // Dark Blue
|
||||
"dark_green", // Dark Green
|
||||
"dark_cyan", // Dark Cyan
|
||||
"dark_red", // Dark Red
|
||||
"dark_magenta", // Dark Magenta
|
||||
"dark_yellow", // Dark Yellow
|
||||
"gray", // Dark White
|
||||
"dark_gray", // Bright Black
|
||||
"blue", // Bright Blue
|
||||
"green", // Bright Green
|
||||
"cyan", // Bright Cyan
|
||||
"red", // Bright Red
|
||||
"magenta", // Bright Magenta
|
||||
"yellow", // Bright Yellow
|
||||
"white" // Bright White
|
||||
};
|
||||
|
||||
public string Name => "concfg Parser";
|
||||
public string Name { get; } = "concfg Parser";
|
||||
|
||||
static uint ParseColor(string arg)
|
||||
{
|
||||
System.Drawing.Color col = System.Drawing.ColorTranslator.FromHtml(arg);
|
||||
return RGB(col.R, col.G, col.B);
|
||||
}
|
||||
|
||||
static XmlDocument loadJsonFile(string schemeName)
|
||||
{
|
||||
XmlDocument xmlDoc = new XmlDocument();
|
||||
foreach (string path in Scheme.GetSearchPaths(schemeName, ".json")
|
||||
.Where(File.Exists))
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = File.ReadAllBytes(path);
|
||||
var reader = JsonReaderWriterFactory.CreateJsonReader(data, System.Xml.XmlDictionaryReaderQuotas.Max);
|
||||
xmlDoc.Load(reader);
|
||||
return xmlDoc;
|
||||
}
|
||||
catch (XmlException /*e*/) { /* failed to parse */ }
|
||||
catch (IOException /*e*/) { /* failed to find */ }
|
||||
catch (UnauthorizedAccessException /*e*/) { /* unauthorized */ }
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
public bool CanParse(string schemeName) =>
|
||||
string.Equals(Path.GetExtension(schemeName), FileExtension, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public ColorScheme ParseScheme(string schemeName, bool reportErrors = false)
|
||||
{
|
||||
XmlDocument xmlDoc = loadJsonFile(schemeName);
|
||||
XmlDocument xmlDoc = LoadJsonFile(schemeName);
|
||||
if (xmlDoc == null) return null;
|
||||
|
||||
try
|
||||
{
|
||||
XmlNode root = xmlDoc.DocumentElement;
|
||||
XmlNodeList children = root.ChildNodes;
|
||||
uint[] colorTable = new uint[COLOR_TABLE_SIZE]; ;
|
||||
for (int i = 0; i < COLOR_TABLE_SIZE; i++)
|
||||
uint[] colorTable = new uint[ColorTableSize]; ;
|
||||
for (int i = 0; i < ColorTableSize; i++)
|
||||
{
|
||||
string name = CONCFG_COLOR_NAMES[i];
|
||||
string name = ConcfgColorNames[i];
|
||||
var node = children.OfType<XmlNode>().Where(n => n.Name == name).Single();
|
||||
colorTable[i] = ParseColor(node.InnerText);
|
||||
}
|
||||
|
@ -87,8 +68,8 @@ namespace ColorTool
|
|||
var parts = popupNode.InnerText.Split(',');
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
var foregroundIndex = (CONCFG_COLOR_NAMES as IList<string>).IndexOf(parts[0]);
|
||||
var backgroundIndex = (CONCFG_COLOR_NAMES as IList<string>).IndexOf(parts[1]);
|
||||
var foregroundIndex = (ConcfgColorNames as IList<string>).IndexOf(parts[0]);
|
||||
var backgroundIndex = (ConcfgColorNames as IList<string>).IndexOf(parts[1]);
|
||||
if (foregroundIndex != -1 && backgroundIndex != -1)
|
||||
{
|
||||
popupForeground = colorTable[foregroundIndex];
|
||||
|
@ -106,8 +87,8 @@ namespace ColorTool
|
|||
var parts = screenNode.InnerText.Split(',');
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
var foregroundIndex = (CONCFG_COLOR_NAMES as IList<string>).IndexOf(parts[0]);
|
||||
var backgroundIndex = (CONCFG_COLOR_NAMES as IList<string>).IndexOf(parts[1]);
|
||||
var foregroundIndex = (ConcfgColorNames as IList<string>).IndexOf(parts[0]);
|
||||
var backgroundIndex = (ConcfgColorNames as IList<string>).IndexOf(parts[1]);
|
||||
if (foregroundIndex != -1 && backgroundIndex != -1)
|
||||
{
|
||||
screenForeground = colorTable[foregroundIndex];
|
||||
|
@ -116,18 +97,45 @@ namespace ColorTool
|
|||
}
|
||||
}
|
||||
|
||||
var consoleAttributes = new ConsoleAttributes { background = screenBackground, foreground = screenForeground, popupBackground = popupBackground, popupForeground = popupForeground };
|
||||
return new ColorScheme { colorTable = colorTable, consoleAttributes = consoleAttributes };
|
||||
var consoleAttributes = new ConsoleAttributes(screenBackground, screenForeground, popupBackground, popupForeground);
|
||||
return new ColorScheme(colorTable, consoleAttributes);
|
||||
}
|
||||
catch (Exception /*e*/)
|
||||
{
|
||||
if (reportErrors)
|
||||
{
|
||||
Console.WriteLine("failes to load json scheme");
|
||||
Console.WriteLine("failed to load json scheme");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static uint ParseColor(string arg)
|
||||
{
|
||||
System.Drawing.Color col = System.Drawing.ColorTranslator.FromHtml(arg);
|
||||
return RGB(col.R, col.G, col.B);
|
||||
}
|
||||
|
||||
private static XmlDocument LoadJsonFile(string schemeName)
|
||||
{
|
||||
XmlDocument xmlDoc = new XmlDocument();
|
||||
foreach (string path in SchemeManager.GetSearchPaths(schemeName, FileExtension)
|
||||
.Where(File.Exists))
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = File.ReadAllBytes(path);
|
||||
var reader = JsonReaderWriterFactory.CreateJsonReader(data, System.Xml.XmlDictionaryReaderQuotas.Max);
|
||||
xmlDoc.Load(reader);
|
||||
return xmlDoc;
|
||||
}
|
||||
catch (XmlException /*e*/) { /* failed to parse */ }
|
||||
catch (IOException /*e*/) { /* failed to find */ }
|
||||
catch (UnauthorizedAccessException /*e*/) { /* unauthorized */ }
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +1,94 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Xml;
|
||||
using static ColorTool.ConsoleAPI;
|
||||
|
||||
namespace ColorTool
|
||||
namespace ColorTool.SchemeParsers
|
||||
{
|
||||
class XmlSchemeParser : ISchemeParser
|
||||
{
|
||||
// In Windows Color Table order
|
||||
static string[] PLIST_COLOR_NAMES = {
|
||||
"Ansi 0 Color", // DARK_BLACK
|
||||
"Ansi 4 Color", // DARK_BLUE
|
||||
"Ansi 2 Color", // DARK_GREEN
|
||||
"Ansi 6 Color", // DARK_CYAN
|
||||
"Ansi 1 Color", // DARK_RED
|
||||
"Ansi 5 Color", // DARK_MAGENTA
|
||||
"Ansi 3 Color", // DARK_YELLOW
|
||||
"Ansi 7 Color", // DARK_WHITE
|
||||
"Ansi 8 Color", // BRIGHT_BLACK
|
||||
"Ansi 12 Color", // BRIGHT_BLUE
|
||||
"Ansi 10 Color", // BRIGHT_GREEN
|
||||
"Ansi 14 Color", // BRIGHT_CYAN
|
||||
"Ansi 9 Color", // BRIGHT_RED
|
||||
"Ansi 13 Color", // BRIGHT_MAGENTA
|
||||
"Ansi 11 Color", // BRIGHT_YELLOW
|
||||
"Ansi 15 Color" // BRIGHT_WHITE
|
||||
private static readonly string[] PListColorNames =
|
||||
{
|
||||
"Ansi 0 Color", // Dark Black
|
||||
"Ansi 4 Color", // Dark Blue
|
||||
"Ansi 2 Color", // Dark Green
|
||||
"Ansi 6 Color", // Dark Cyan
|
||||
"Ansi 1 Color", // Dark Red
|
||||
"Ansi 5 Color", // Dark Magenta
|
||||
"Ansi 3 Color", // Dark Yellow
|
||||
"Ansi 7 Color", // Dark White
|
||||
"Ansi 8 Color", // Bright Black
|
||||
"Ansi 12 Color", // Bright Blue
|
||||
"Ansi 10 Color", // Bright Green
|
||||
"Ansi 14 Color", // Bright Cyan
|
||||
"Ansi 9 Color", // Bright Red
|
||||
"Ansi 13 Color", // Bright Magenta
|
||||
"Ansi 11 Color", // Bright Yellow
|
||||
"Ansi 15 Color" // Bright White
|
||||
};
|
||||
static string FG_KEY = "Foreground Color";
|
||||
static string BG_KEY = "Background Color";
|
||||
static string RED_KEY = "Red Component";
|
||||
static string GREEN_KEY = "Green Component";
|
||||
static string BLUE_KEY = "Blue Component";
|
||||
|
||||
public string Name => "iTerm Parser";
|
||||
private const string ForegroundKey = "Foreground Color";
|
||||
private const string BackgroundKey = "Background Color";
|
||||
private const string RedKey = "Red Component";
|
||||
private const string GreenKey = "Green Component";
|
||||
private const string BlueKey = "Blue Component";
|
||||
private const string FileExtension = ".itermcolors";
|
||||
|
||||
static bool parseRgbFromXml(XmlNode components, ref uint rgb)
|
||||
public string Name { get; } = "iTerm Parser";
|
||||
|
||||
public bool CanParse(string schemeName) =>
|
||||
string.Equals(Path.GetExtension(schemeName), FileExtension, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public ColorScheme ParseScheme(string schemeName, bool reportErrors = false)
|
||||
{
|
||||
XmlDocument xmlDoc = LoadXmlScheme(schemeName); // Create an XML document object
|
||||
if (xmlDoc == null) return null;
|
||||
XmlNode root = xmlDoc.GetElementsByTagName("dict")[0];
|
||||
XmlNodeList children = root.ChildNodes;
|
||||
|
||||
uint[] colorTable = new uint[ColorTableSize];
|
||||
uint? fgColor = null, bgColor = null;
|
||||
int colorsFound = 0;
|
||||
bool success = false;
|
||||
foreach (var tableEntry in children.OfType<XmlNode>().Where(_ => _.Name == "key"))
|
||||
{
|
||||
uint rgb = 0;
|
||||
int index = -1;
|
||||
XmlNode components = tableEntry.NextSibling;
|
||||
success = ParseRgbFromXml(components, ref rgb);
|
||||
if (!success) { break; }
|
||||
else if (tableEntry.InnerText == ForegroundKey) { fgColor = rgb; }
|
||||
else if (tableEntry.InnerText == BackgroundKey) { bgColor = rgb; }
|
||||
else if (-1 != (index = Array.IndexOf(PListColorNames, tableEntry.InnerText)))
|
||||
{ colorTable[index] = rgb; colorsFound++; }
|
||||
}
|
||||
if (colorsFound < ColorTableSize)
|
||||
{
|
||||
if (reportErrors)
|
||||
{
|
||||
Console.WriteLine(Resources.InvalidNumberOfColors);
|
||||
}
|
||||
success = false;
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var consoleAttributes = new ConsoleAttributes(bgColor, fgColor, null, null);
|
||||
return new ColorScheme(colorTable, consoleAttributes);
|
||||
}
|
||||
|
||||
private static bool ParseRgbFromXml(XmlNode components, ref uint rgb)
|
||||
{
|
||||
int r = -1;
|
||||
int g = -1;
|
||||
|
@ -51,15 +98,15 @@ namespace ColorTool
|
|||
{
|
||||
if (c.Name == "key")
|
||||
{
|
||||
if (c.InnerText == RED_KEY)
|
||||
if (c.InnerText == RedKey)
|
||||
{
|
||||
r = (int)(255 * Convert.ToDouble(c.NextSibling.InnerText, CultureInfo.InvariantCulture));
|
||||
}
|
||||
else if (c.InnerText == GREEN_KEY)
|
||||
else if (c.InnerText == GreenKey)
|
||||
{
|
||||
g = (int)(255 * Convert.ToDouble(c.NextSibling.InnerText, CultureInfo.InvariantCulture));
|
||||
}
|
||||
else if (c.InnerText == BLUE_KEY)
|
||||
else if (c.InnerText == BlueKey)
|
||||
{
|
||||
b = (int)(255 * Convert.ToDouble(c.NextSibling.InnerText, CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
@ -78,11 +125,10 @@ namespace ColorTool
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
static XmlDocument loadXmlScheme(string schemeName)
|
||||
private static XmlDocument LoadXmlScheme(string schemeName)
|
||||
{
|
||||
XmlDocument xmlDoc = new XmlDocument(); // Create an XML document object
|
||||
foreach (string path in Scheme.GetSearchPaths(schemeName, ".itermcolors")
|
||||
foreach (string path in SchemeManager.GetSearchPaths(schemeName, FileExtension)
|
||||
.Where(File.Exists))
|
||||
{
|
||||
try
|
||||
|
@ -97,46 +143,5 @@ namespace ColorTool
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public ColorScheme ParseScheme(string schemeName, bool reportErrors = false)
|
||||
{
|
||||
XmlDocument xmlDoc = loadXmlScheme(schemeName); // Create an XML document object
|
||||
if (xmlDoc == null) return null;
|
||||
XmlNode root = xmlDoc.GetElementsByTagName("dict")[0];
|
||||
XmlNodeList children = root.ChildNodes;
|
||||
|
||||
uint[] colorTable = new uint[COLOR_TABLE_SIZE];
|
||||
uint? fgColor = null, bgColor = null;
|
||||
int colorsFound = 0;
|
||||
bool success = false;
|
||||
foreach (var tableEntry in children.OfType<XmlNode>().Where(_ => _.Name == "key"))
|
||||
{
|
||||
uint rgb = 0;
|
||||
int index = -1;
|
||||
XmlNode components = tableEntry.NextSibling;
|
||||
success = parseRgbFromXml(components, ref rgb);
|
||||
if (!success) { break; }
|
||||
else if (tableEntry.InnerText == FG_KEY) { fgColor = rgb; }
|
||||
else if (tableEntry.InnerText == BG_KEY) { bgColor = rgb; }
|
||||
else if (-1 != (index = Array.IndexOf(PLIST_COLOR_NAMES, tableEntry.InnerText)))
|
||||
{ colorTable[index] = rgb; colorsFound++; }
|
||||
}
|
||||
if (colorsFound < COLOR_TABLE_SIZE)
|
||||
{
|
||||
if (reportErrors)
|
||||
{
|
||||
Console.WriteLine(Resources.InvalidNumberOfColors);
|
||||
}
|
||||
success = false;
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var consoleAttributes = new ConsoleAttributes { foreground = fgColor, background = bgColor };
|
||||
return new ColorScheme { colorTable = colorTable, consoleAttributes = consoleAttributes };
|
||||
}
|
||||
}
|
||||
}
|
66
tools/ColorTool/ColorTool/SchemeWriters/IniSchemeWriter.cs
Normal file
66
tools/ColorTool/ColorTool/SchemeWriters/IniSchemeWriter.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
using ColorTool.SchemeParsers;
|
||||
using System;
|
||||
using static ColorTool.ConsoleAPI;
|
||||
|
||||
namespace ColorTool.SchemeWriters
|
||||
{
|
||||
class IniSchemeWriter
|
||||
{
|
||||
public bool ExportCurrentAsIni(string outputPath)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO_EX csbiex = CONSOLE_SCREEN_BUFFER_INFO_EX.Create();
|
||||
IntPtr hOut = GetStdOutputHandle();
|
||||
bool success = GetConsoleScreenBufferInfoEx(hOut, ref csbiex);
|
||||
if (success)
|
||||
{
|
||||
try
|
||||
{
|
||||
// StreamWriter can fail for a variety of file system reasons so catch exceptions and print message.
|
||||
using (System.IO.StreamWriter file = new System.IO.StreamWriter(outputPath))
|
||||
{
|
||||
file.WriteLine("[table]");
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
string line = IniSchemeParser.ColorNames[i];
|
||||
line += " = ";
|
||||
uint color = csbiex.ColorTable[i];
|
||||
uint r = color & (0x000000ff);
|
||||
uint g = (color & (0x0000ff00)) >> 8;
|
||||
uint b = (color & (0x00ff0000)) >> 16;
|
||||
line += r + "," + g + "," + b;
|
||||
file.WriteLine(line);
|
||||
}
|
||||
|
||||
file.WriteLine();
|
||||
file.WriteLine("[screen]");
|
||||
var forgroundIndex = csbiex.wAttributes & 0xF;
|
||||
var backgroundIndex = csbiex.wAttributes >> 4;
|
||||
file.WriteLine($"FOREGROUND = {IniSchemeParser.ColorNames[forgroundIndex]}");
|
||||
file.WriteLine($"BACKGROUND = {IniSchemeParser.ColorNames[backgroundIndex]}");
|
||||
|
||||
file.WriteLine();
|
||||
file.WriteLine("[popup]");
|
||||
forgroundIndex = csbiex.wPopupAttributes & 0xF;
|
||||
backgroundIndex = csbiex.wPopupAttributes >> 4;
|
||||
file.WriteLine($"FOREGROUND = {IniSchemeParser.ColorNames[forgroundIndex]}");
|
||||
file.WriteLine($"BACKGROUND = {IniSchemeParser.ColorNames[backgroundIndex]}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Failed to get console information.");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue