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:
Michael Niksa 2019-04-29 12:12:01 -07:00 committed by GitHub
commit 723efc70e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 883 additions and 774 deletions

View file

@ -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);
}
}
}

View 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");
}
}
}

View file

@ -2,7 +2,8 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net46</TargetFramework>
<TargetFramework>net461</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<LangVersion>latest</LangVersion>
</PropertyGroup>
</Project>

View file

@ -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;
}
}

View file

@ -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; }
}
}

View file

@ -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();
}
}
}
}

View file

@ -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);
}
}
}

View 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);
}
}

View file

@ -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);
}
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View 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));
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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 };
}
}
}

View 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;
}
}
}