diff --git a/src/WpfMath.Tests/ParserTests.fs b/src/WpfMath.Tests/ParserTests.fs index a01a1f54..9494ef1a 100644 --- a/src/WpfMath.Tests/ParserTests.fs +++ b/src/WpfMath.Tests/ParserTests.fs @@ -40,11 +40,28 @@ type ParserTests() = <| sprintf @"\left%sa\right%s" left right <| (formula <| fenced (openBrace lResult) (char 'a') (closeBrace rResult)) + [] + [] + [] + 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) + [] 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)) + + [] + let ``Non-existing delimiter should throw exception`` () = + let markup = @"\left x\right)" + Assert.Throws(fun () -> TexFormulaParser().Parse(markup) |> ignore) [] let ``Expression in braces should be parsed`` () = diff --git a/src/WpfMath.Tests/Utils.fs b/src/WpfMath.Tests/Utils.fs index ab29c78a..b323d136 100644 --- a/src/WpfMath.Tests/Utils.fs +++ b/src/WpfMath.Tests/Utils.fs @@ -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) : BigOperatorAtom = BigOperatorAtom(baseAtom, null, null, useVertScripts) -let opWithScripts (baseAtom : Atom) (subscript : Atom) (superscript : Atom) (useVertScripts : System.Nullable) +let opWithScripts (baseAtom : Atom) (subscript : Atom) (superscript : Atom) (useVertScripts : System.Nullable) : 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) @@ -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 diff --git a/src/WpfMath/Data/TexFormulaSettings.xml b/src/WpfMath/Data/TexFormulaSettings.xml index 844c3aaf..574f2eb9 100644 --- a/src/WpfMath/Data/TexFormulaSettings.xml +++ b/src/WpfMath/Data/TexFormulaSettings.xml @@ -39,9 +39,10 @@ +The symbolnames must be defined in "TexSymbols.xml" as delimiters (del="true")!! --> + diff --git a/src/WpfMath/Data/TexSymbols.xml b/src/WpfMath/Data/TexSymbols.xml index 0a98b442..649a6cd2 100644 --- a/src/WpfMath/Data/TexSymbols.xml +++ b/src/WpfMath/Data/TexSymbols.xml @@ -2,6 +2,9 @@ + + + diff --git a/src/WpfMath/FencedAtom.cs b/src/WpfMath/FencedAtom.cs index 38dc48e2..1235c47d 100644 --- a/src/WpfMath/FencedAtom.cs +++ b/src/WpfMath/FencedAtom.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace WpfMath { @@ -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); @@ -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); diff --git a/src/WpfMath/SymbolAtom.cs b/src/WpfMath/SymbolAtom.cs index 56dfd740..555d57a6 100644 --- a/src/WpfMath/SymbolAtom.cs +++ b/src/WpfMath/SymbolAtom.cs @@ -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 { + /// + /// Special name of empty delimiter symbol that shouldn't be rendered. + /// + internal const string EmptyDelimiterName = "_emptyDelimiter"; + // Dictionary of definitions of all symbols, keyed by name. private static IDictionary symbols; @@ -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) diff --git a/src/WpfMath/TexFormulaParser.cs b/src/WpfMath/TexFormulaParser.cs index c7322aca..ad948cc3 100644 --- a/src/WpfMath/TexFormulaParser.cs +++ b/src/WpfMath/TexFormulaParser.cs @@ -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; @@ -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");