Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for empty delimiters #58

Merged
merged 3 commits into from
Feb 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/WpfMath.Tests/ParserTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,28 @@ type ParserTests() =
<| sprintf @"\left%sa\right%s" left right
<| (formula <| fenced (openBrace lResult) (char 'a') (closeBrace rResult))

[<Theory>]
[<InlineData(".", ")", true, false)>]
[<InlineData("(", ".", false, true)>]
let ``Empty delimiters should work`` (left : string, right : string, isLeftEmpty : bool, isRightEmpty : bool) =
let empty = brace SymbolAtom.EmptyDelimiterName TexAtomType.Ordinary
let leftBrace = if isLeftEmpty then empty else (openBrace "lbrack")
let rightBrace = if isRightEmpty then empty else (closeBrace "rbrack")

assertParseResult
<| sprintf @"\left%sa\right%s" left right
<| (formula <| fenced leftBrace (char 'a') rightBrace)

[<Fact>]
let ``Unmatched delimiters should work`` () =
assertParseResult
<| @"\left)a\right|"
<| (formula <| fenced (closeBrace "rbrack") (char 'a') (SymbolAtom("vert", TexAtomType.Ordinary, true)))
<| (formula <| fenced (closeBrace "rbrack") (char 'a') (brace "vert" TexAtomType.Ordinary))

[<Fact>]
let ``Non-existing delimiter should throw exception`` () =
let markup = @"\left x\right)"
Assert.Throws<TexParseException>(fun () -> TexFormulaParser().Parse(markup) |> ignore)

[<Fact>]
let ``Expression in braces should be parsed`` () =
Expand Down
7 changes: 4 additions & 3 deletions src/WpfMath.Tests/Utils.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ let formula (root : Atom) : TexFormula =
let char (c : char) : CharAtom = CharAtom(c)
let styledChar (c : char, style:string) : CharAtom = CharAtom(c, style)
let op (baseAtom : Atom) (useVertScripts : System.Nullable<bool>) : BigOperatorAtom = BigOperatorAtom(baseAtom, null, null, useVertScripts)
let opWithScripts (baseAtom : Atom) (subscript : Atom) (superscript : Atom) (useVertScripts : System.Nullable<bool>)
let opWithScripts (baseAtom : Atom) (subscript : Atom) (superscript : Atom) (useVertScripts : System.Nullable<bool>)
: BigOperatorAtom = BigOperatorAtom(baseAtom, subscript, superscript, useVertScripts)
let group (groupedAtom: Atom) : TypedAtom = TypedAtom(groupedAtom, TexAtomType.Ordinary, TexAtomType.Ordinary)
let symbol (name : string) : SymbolAtom = SymbolAtom(name, TexAtomType.BinaryOperator, false)
Expand All @@ -19,5 +19,6 @@ let row (children : Atom seq) : RowAtom =
result
let fenced left body right : FencedAtom = FencedAtom(body, left, right)

let openBrace (name : string) : SymbolAtom = SymbolAtom(name, TexAtomType.Opening, true)
let closeBrace (name : string) : SymbolAtom = SymbolAtom(name, TexAtomType.Closing, true)
let brace (name : string) (braceType : TexAtomType) : SymbolAtom = SymbolAtom(name, braceType, true)
let openBrace (name : string) : SymbolAtom = brace name TexAtomType.Opening
let closeBrace (name : string) : SymbolAtom = brace name TexAtomType.Closing
3 changes: 2 additions & 1 deletion src/WpfMath/Data/TexFormulaSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@
<!-- character-to-delimiter-mappings

These are used in the method "embrace(char,char)" from the class "Formula".
The symbolnames must be defined in "TeXSymbols.xml" as delimiters (del="true")!! -->
The symbolnames must be defined in "TexSymbols.xml" as delimiters (del="true")!! -->

<CharacterToDelimiterMappings>
<Map char="." symbol="_emptyDelimiter"/>
<Map char="(" symbol="lbrack"/>
<Map char=")" symbol="rbrack"/>
<Map char="[" symbol="lsqbrack"/>
Expand Down
3 changes: 3 additions & 0 deletions src/WpfMath/Data/TexSymbols.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

<TeXSymbols>

<!-- special -->
<Symbol name="_emptyDelimiter" type="ord" del="true"/>

<!-- miscellaneous symbols -->

<Symbol name="%" type="ord"/>
Expand Down
7 changes: 2 additions & 5 deletions src/WpfMath/FencedAtom.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WpfMath
{
Expand Down Expand Up @@ -57,7 +54,7 @@ public override Box CreateBox(TexEnvironment environment)
var minHeight = Math.Max((delta / 500) * delimeterFactor, 2 * delta - delimeterShortfall);

// Create and add box for left delimeter.
if (LeftDelimeter != null)
if (LeftDelimeter != null && LeftDelimeter.Name != SymbolAtom.EmptyDelimiterName)
{
var leftDelimeterBox = DelimiterFactory.CreateBox(this.LeftDelimeter.Name, minHeight, environment);
CentreBox(leftDelimeterBox, axis);
Expand All @@ -76,7 +73,7 @@ public override Box CreateBox(TexEnvironment environment)
resultBox.Add(Glue.CreateBox(this.BaseAtom.GetRightType(), TexAtomType.Closing, environment));

// Create and add box for right delimeter.
if (this.RightDelimeter != null)
if (RightDelimeter != null && RightDelimeter.Name != SymbolAtom.EmptyDelimiterName)
{
var rightDelimeterBox = DelimiterFactory.CreateBox(this.RightDelimeter.Name, minHeight, environment);
CentreBox(rightDelimeterBox, axis);
Expand Down
9 changes: 6 additions & 3 deletions src/WpfMath/SymbolAtom.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WpfMath
{
// Atom representing symbol (non-alphanumeric character).
internal class SymbolAtom : CharSymbol
{
/// <summary>
/// Special name of empty delimiter symbol that shouldn't be rendered.
/// </summary>
internal const string EmptyDelimiterName = "_emptyDelimiter";

// Dictionary of definitions of all symbols, keyed by name.
private static IDictionary<string, SymbolAtom> symbols;

Expand Down Expand Up @@ -45,7 +48,7 @@ public static SymbolAtom GetAtom(string name)

public static bool TryGetAtom(string name, out SymbolAtom atom)
{
return symbols.TryGetValue(name, out atom);
return symbols.TryGetValue(name, out atom);
}

public SymbolAtom(SymbolAtom symbolAtom, TexAtomType type)
Expand Down
5 changes: 4 additions & 1 deletion src/WpfMath/TexFormulaParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ internal static string GetDelimeterMapping(char character)

internal static SymbolAtom GetDelimiterSymbol(string name)
{
if (name == null)
return null;

var result = SymbolAtom.GetAtom(name);
if (!result.IsDelimeter)
return null;
Expand Down Expand Up @@ -154,7 +157,7 @@ private DelimiterInfo ParseUntilDelimiter(string value, ref int position, string
throw new TexParseException("Cannot find closing delimiter");

var bodyRow = embeddedFormula.RootAtom as RowAtom;
var lastAtom = embeddedFormula.RootAtom as SymbolAtom ?? bodyRow.Elements.LastOrDefault();
var lastAtom = bodyRow?.Elements.LastOrDefault() ?? embeddedFormula.RootAtom;
var lastDelimiter = lastAtom as SymbolAtom;
if (lastDelimiter == null || !lastDelimiter.IsDelimeter)
throw new TexParseException($"Cannot find closing delimiter; got {lastDelimiter} instead");
Expand Down