Skip to content

Commit

Permalink
Generalize PredefinedColorParser as an IColorParser instance (#165)
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Sep 16, 2019
1 parent 29bf5fe commit 3bd5e81
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 48 deletions.
3 changes: 2 additions & 1 deletion src/WpfMath.Tests/ParserExceptionTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ open Xunit

open WpfMath
open WpfMath.Atoms
open WpfMath.Colors
open WpfMath.Exceptions
open WpfMath.Parsers
open WpfMath.Tests.Utils
Expand Down Expand Up @@ -34,6 +35,6 @@ let ``Incorrect command parser behavior should be detected``(): unit =
member __.ProcessCommand _ =
CommandProcessingResult(SpaceAtom(null), 0) }
let parserRegistry = Map([| "dummy", incorrectParser |])
let parser = TexFormulaParser(parserRegistry)
let parser = TexFormulaParser(parserRegistry, PredefinedColorParser.Instance)
let ex = Assert.Throws<TexParseException>(Action(fun () -> ignore <| parser.Parse("\dummy")))
Assert.Contains("NextPosition = 0", ex.Message)
25 changes: 25 additions & 0 deletions src/WpfMath.Tests/PredefinedColorParserTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module WpfMath.Tests.PredefinedColorParserTests

open System.Windows.Media

open Xunit

open WpfMath.Colors

let parser = PredefinedColorParser.Instance

[<Fact>]
let ``PredefinedColorParser parses a correctly defined color``(): unit =
Assert.Equal(Color.FromRgb(237uy, 27uy, 35uy), parser.Parse([| "red" |]).Value)

[<Fact>]
let ``PredefinedColorParser returns null for wrong input``(): unit =
Assert.Null(parser.Parse([| "nonexistent-color" |]))

[<Fact>]
let ``PredefinedColorParser returns null for empty input``(): unit =
Assert.Null(parser.Parse(Array.empty))

[<Fact>]
let ``PredefinedColorParser returns null for too long input``(): unit =
Assert.Null(parser.Parse([| "red"; "green" |]))
1 change: 1 addition & 0 deletions src/WpfMath.Tests/WpfMath.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<Compile Include="ApprovalTestUtils.fs" />
<Compile Include="Utils.fs" />
<Compile Include="BoxTests.fs" />
<Compile Include="PredefinedColorParserTests.fs" />
<Compile Include="CharBoxTests.fs" />
<Compile Include="DefaultTexFontTests.fs" />
<Compile Include="GeometryHelperTests.fs" />
Expand Down
14 changes: 14 additions & 0 deletions src/WpfMath/Colors/IColorParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Windows.Media;

namespace WpfMath.Colors
{
/// <summary>A parser for colors.</summary>
public interface IColorParser
{
/// <summary>Parses the color components.</summary>
/// <param name="components">A sequence of the components that were separated by comma.</param>
/// <returns>Either a parsed color or <c>null</c> if it cannot be parsed.</returns>
Color? Parse(IEnumerable<string> components);
}
}
60 changes: 60 additions & 0 deletions src/WpfMath/Colors/PredefinedColorParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows.Media;
using System.Xml.Linq;

namespace WpfMath.Colors
{
internal class PredefinedColorParser : IColorParser
{
private const string ResourceName = TexUtilities.ResourcesDataDirectory + "PredefinedColors.xml";
public static readonly PredefinedColorParser Instance = new PredefinedColorParser(ResourceName);

private readonly IReadOnlyDictionary<string, Color> _colors;

private PredefinedColorParser(string resourceName)
{
using (var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
var doc = XDocument.Load(resource);
_colors = Parse(doc.Root);
}
}

public Color? Parse(IEnumerable<string> components)
{
// Return a color iff components contain only one element, and it is contained in the _colors dictionary.
var firstItem = true;
Color? color = null;
foreach (var component in components)
{
if (!firstItem)
return null;

var colorName = component;
if (_colors.TryGetValue(colorName, out var parsedColor))
color = parsedColor;

firstItem = false;
}

return color;
}

private Dictionary<string, Color> Parse(XElement rootElement)
{
var colors = new Dictionary<string, Color>();
foreach (var colorElement in rootElement.Elements("color"))
{
var name = colorElement.AttributeValue("name");
var r = colorElement.AttributeValue("r");
var g = colorElement.AttributeValue("g");
var b = colorElement.AttributeValue("b");
colors.Add(name, Color.FromRgb(Convert.ToByte(r), Convert.ToByte(g), Convert.ToByte(b)));
}

return colors;
}
}
}
34 changes: 0 additions & 34 deletions src/WpfMath/PredefinedColorParser.cs

This file was deleted.

38 changes: 26 additions & 12 deletions src/WpfMath/TexFormulaParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Windows;
using System.Windows.Media;
using WpfMath.Atoms;
using WpfMath.Colors;
using WpfMath.Exceptions;
using WpfMath.Parsers;

Expand Down Expand Up @@ -49,7 +50,6 @@ public class TexFormulaParser
private static HashSet<string> textStyles;
private static readonly IDictionary<string, Func<SourceSpan, TexFormula>> predefinedFormulas =
new Dictionary<string, Func<SourceSpan, TexFormula>>();
private static IDictionary<string, Color> predefinedColors;

private static readonly string[][] delimiterNames =
{
Expand All @@ -68,8 +68,6 @@ public class TexFormulaParser
#endregion
static TexFormulaParser()
{
predefinedColors = new Dictionary<string, Color>();

Initialize();
}

Expand All @@ -95,9 +93,6 @@ private static void Initialize()
delimeters = formulaSettingsParser.GetDelimiterMappings();
textStyles = formulaSettingsParser.GetTextStyles();

var colorParser = new PredefinedColorParser();
colorParser.Parse(predefinedColors);

var predefinedFormulasParser = new TexPredefinedFormulaParser();
predefinedFormulasParser.Parse(predefinedFormulas);
}
Expand Down Expand Up @@ -140,12 +135,21 @@ private static bool IsWhiteSpace(char ch)
/// <summary>A registry for additional commands.</summary>
private readonly IReadOnlyDictionary<string, ICommandParser> _commandRegistry;

internal TexFormulaParser(IReadOnlyDictionary<string, ICommandParser> commandRegistry)
/// <summary>A color parser for cases when the color model isn't specified.</summary>
private readonly IColorParser _defaultColorParser;

internal TexFormulaParser(
IReadOnlyDictionary<string, ICommandParser> commandRegistry,
IColorParser defaultColorParser)
{
_commandRegistry = commandRegistry;
_defaultColorParser = defaultColorParser;
}

public TexFormulaParser() : this(StandardCommands.Dictionary) {}
public TexFormulaParser() : this(
StandardCommands.Dictionary,
PredefinedColorParser.Instance)
{}

public TexFormula Parse(string value, string textStyle = null)
{
Expand Down Expand Up @@ -468,9 +472,14 @@ private Atom ProcessCommand(
var bodyFormula = Parse(bodyValue, formula.TextStyle, environment.CreateChildEnvironment());
source = value.Segment(start, position - start);

if (predefinedColors.TryGetValue(colorName, out Color color))
var color = _defaultColorParser.Parse(new[] {colorName});
if (color != null)
{
return new StyledAtom(source, bodyFormula.RootAtom, null, new SolidColorBrush(color));
return new StyledAtom(
source,
bodyFormula.RootAtom,
null,
new SolidColorBrush(color.Value));
}
else
{
Expand All @@ -491,11 +500,16 @@ private Atom ProcessCommand(
var bodyValue = ReadElement(value, ref position);
var bodyFormula = this.Parse(bodyValue, formula.TextStyle, environment.CreateChildEnvironment());
source = value.Segment(start, position - start);
var color = _defaultColorParser.Parse(new[] {colorName});

if (predefinedColors.TryGetValue(colorName, out var color))
if (color != null)
{
source = value.Segment(start, position - start);
return new StyledAtom(source, bodyFormula.RootAtom, new SolidColorBrush(color), null);
return new StyledAtom(
source,
bodyFormula.RootAtom,
new SolidColorBrush(color.Value),
null);
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion src/WpfMath/TexUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
internal static class TexUtilities
{
public static readonly string ResourcesDataDirectory = "WpfMath.Data.";
public const string ResourcesDataDirectory = "WpfMath.Data.";

public const double FloatPrecision = 0.0000001;

Expand Down

0 comments on commit 3bd5e81

Please sign in to comment.