Beispiel #1
0
        public void ForAsciiHandlesAllInputs()
        {
            for (sbyte i = -36 + 1; i != -36; i++) // Break loop at arbitrary negative value (-36)
            {
                switch (i)
                {
                case var _ when i < 0:
                    Assert.Throws <System.ArgumentOutOfRangeException>(
                        () => LaTeXSettings.ForAscii(i)
                        );
                    break;

                case var _ when i <= ' ':
                case (sbyte)'\u007F':
                case (sbyte)'$':
                case (sbyte)'%':
                case (sbyte)'#':
                case (sbyte)'&':
                case (sbyte)'~':
                case (sbyte)'\'':
                case (sbyte)'^':
                case (sbyte)'_':
                case (sbyte)'{':
                case (sbyte)'}':
                case (sbyte)'\\':
                    Assert.Null(LaTeXSettings.ForAscii(i));
                    break;

                default:
                    Assert.NotNull(LaTeXSettings.ForAscii(i));
                    break;
                }
            }
        }
Beispiel #2
0
        public void CommandForAtomIgnoresInnerLists()
        {
            var atom = new Atoms.Accent("\u0308", new MathList(new Atoms.Number("1")));

            atom.Superscript.Add(new Atoms.Number("4"));
            atom.Subscript.Add(new Atoms.Variable("x"));
            Assert.Equal("ddot", LaTeXSettings.CommandForAtom(atom));
        }
Beispiel #3
0
        public void AtomForCommandGeneratesACopy()
        {
            var atom = LaTeXSettings.AtomForCommand("int");

            if (atom == null)
            {
                throw new Xunit.Sdk.NotNullException();
            }
            atom.IndexRange = Range.NotFound;
            var atom2 = LaTeXSettings.AtomForCommand("int");

            if (atom2 == null)
            {
                throw new Xunit.Sdk.NotNullException();
            }
            Assert.Equal(Range.Zero, atom2.IndexRange);
        }
Beispiel #4
0
        /* //Paste this into the C# Interactive, fill <username> yourself
         #r "C:/Users/<username>/source/repos/CSharpMath/Typography/Build/NetStandard/Typography.TextBreak/bin/Debug/netstandard1.3/Typography.TextBreak.dll"
         * using Typography.TextBreak;
         * (int, WordKind, char)[] BreakText(string text) {
         * var breaker = new CustomBreaker();
         * var breakList = new List<BreakAtInfo>();
         * breaker.BreakWords(text);
         * breaker.LoadBreakAtList(breakList);
         * //index is after the boundary -> last one will be out of range
         * return breakList.Select(i => (i.breakAt, i.wordKind, text.ElementAtOrDefault(i.breakAt))).ToArray();
         * }
         * BreakText(@"Here are some text $1 + 12 \frac23 \sqrt4$ $$Display$$ text")
         */
        /* //Version 2
         #r "C:/Users/<username>/source/repos/CSharpMath/Typography/Build/NetStandard/Typography.TextBreak/bin/Debug/netstandard1.3/Typography.TextBreak.dll"
         * using Typography.TextBreak;
         * string BreakText(string text, string seperator = "|")
         * {
         * var breaker = new CustomBreaker();
         * var breakList = new List<BreakAtInfo>();
         * breaker.BreakWords(text);
         * breaker.LoadBreakAtList(breakList);
         * //reverse to ensure earlier inserts do not affect later ones
         * foreach (var @break in breakList.Select(i => i.breakAt).Reverse())
         * text = text.Insert(@break, seperator);
         * return text;
         * }
         * BreakText(@"Here are some text $1 + 12 \frac23 \sqrt4$ $$Display$$ text")
         */
        public static Result <TextAtom> TextAtomFromLaTeX(string latexSource)
        {
            if (string.IsNullOrEmpty(latexSource))
            {
                return(new TextAtom.List(Array.Empty <TextAtom>()));
            }
            int  endAt                   = 0;
            bool?displayMath             = null;
            var  mathLaTeX               = new StringBuilder();
            bool backslashEscape         = false;
            bool afterCommand            = false; // ignore spaces after command
            bool afterNewline            = false;
            int  dollarCount             = 0;
            var  globalAtoms             = new TextAtomListBuilder();
            List <BreakAtInfo> breakList = new List <BreakAtInfo>(); // Roslyn bug that assumes breakList is nullable resulting in warnings so var is not used
            var breaker                  = new CustomBreaker(v => breakList.Add(new BreakAtInfo(v.LatestBreakAt, v.LatestWordKind)))
            {
                BreakNumberAfterText  = true,
                ThrowIfCharOutOfRange = false
            };

            breaker.BreakWords(latexSource);

            Result CheckDollarCount(int startAt, ref int endAt, TextAtomListBuilder atoms)
            {
                switch (dollarCount)
                {
                case 0:
                    break;

                case 1:
                    dollarCount = 0;
                    switch (displayMath)
                    {
                    case true:
                        return("Cannot close display math mode with $");

                    case false:
                        if (atoms.Math(mathLaTeX.ToString(), false, startAt, ref endAt).Error is string error)
                        {
                            return(error);
                        }
                        mathLaTeX.Clear();
                        displayMath = null;
                        break;

                    case null:
                        displayMath = false;
                        break;
                    }
                    break;

                case 2:
                    dollarCount = 0;
                    switch (displayMath)
                    {
                    case true:
                        if (atoms.Math(mathLaTeX.ToString(), true, startAt - 1, ref endAt).Error is string error)
                        {
                            return(error);
                        }
                        mathLaTeX.Clear();
                        displayMath = null;
                        break;

                    case false:
                        return("Cannot close inline math mode with $$");

                    case null:
                        displayMath = true;
                        break;
                    }
                    break;

                default:
                    return("Invalid number of $: " + dollarCount);
                }
                return(Ok());
            }

            Result <int> BuildBreakList(ReadOnlySpan <char> latex, TextAtomListBuilder atoms,
                                        int i, bool oneCharOnly, char stopChar)
            {
                void ParagraphBreak()
                {
                    atoms.Break();
                    atoms.Space(Space.ParagraphIndent);
                }

                for (; i < breakList.Count; i++)
                {
                    void ObtainSection(ReadOnlySpan <char> latexInput, int index,
                                       out int start, out int end, out ReadOnlySpan <char> section, out WordKind kind)
                    {
                        (start, end) = (index == 0 ? 0 : breakList[index - 1].breakAt, breakList[index].breakAt);
                        section      = latexInput.Slice(start, end - start);
                        kind         = breakList[index].wordKind;
                    }

                    ObtainSection(latex, i, out var startAt, out endAt, out var textSection, out var wordKind);
                    bool NextSection(ReadOnlySpan <char> latexInput, ref ReadOnlySpan <char> section)
                    {
                        bool success = ++i < breakList.Count;

                        if (success)
                        {
                            ObtainSection(latexInput, i, out startAt, out endAt, out section, out wordKind);
                        }
                        return(success);
                    }

                    Result <TextAtom> ReadArgumentAtom(ReadOnlySpan <char> latexInput)
                    {
                        backslashEscape = false;
                        var argAtoms = new TextAtomListBuilder();

                        return(BuildBreakList(latexInput, argAtoms, ++i, true, '\0')
                               .Bind(index => { i = index; return argAtoms.Build(); }));
                    }

                    SpanResult <char> ReadArgumentString(ReadOnlySpan <char> latexInput, ref ReadOnlySpan <char> section)
                    {
                        afterCommand = false;
                        if (!NextSection(latexInput, ref section) || section.IsNot('{'))
                        {
                            return(Err("Missing {"));
                        }
                        int endingIndex = -1;
                        //startAt + 1 to not start at the { we started at
                        bool isEscape = false;

                        for (int j = startAt + 1, bracketDepth = 0; j < latexInput.Length; j++)
                        {
                            if (latexInput[j] == '\\')
                            {
                                isEscape = true;
                            }
                            else if (latexInput[j] == '{' && !isEscape)
                            {
                                bracketDepth++;
                            }
                            else if (latexInput[j] == '}' && !isEscape)
                            {
                                if (bracketDepth > 0)
                                {
                                    bracketDepth--;
                                }
                                else
                                {
                                    endingIndex = j; break;
                                }
                            }
                            else
                            {
                                isEscape = false;
                            }
                        }
                        if (endingIndex == -1)
                        {
                            return(Err("Missing }"));
                        }
                        var resultText = latexInput.Slice(endAt, endingIndex - endAt);

                        while (startAt < endingIndex)
                        {
                            _ = NextSection(latexInput, ref section); //this never fails because the above check
                        }
                        return(Ok(resultText));
                    }

                    Result <Color> ReadColor(ReadOnlySpan <char> latexInput, ref ReadOnlySpan <char> section) =>
                    ReadArgumentString(latexInput, ref section).Bind(color =>
                                                                     LaTeXSettings.ParseColor(color.ToString()) is Color value ?
                                                                     Ok(value) :
                                                                     Err("Invalid color: " + color.ToString())
                                                                     );

                    //Nothing should be before dollar sign checking -- dollar sign checking uses continue;
                    atoms.TextLength = startAt;
                    if (textSection.Is('$'))
                    {
                        if (backslashEscape)
                        {
                            if (displayMath != null)
                            {
                                mathLaTeX.Append(@"\$");
                            }
                            else
                            {
                                atoms.Text("$");
                            }
                        }
                        else
                        {
                            dollarCount++;
                            continue;
                        }
                        backslashEscape = false;
                    }
                    else
                    {
                        { if (CheckDollarCount(startAt, ref endAt, atoms).Error is string error)
                          {
                              return(error);
                          }
                        }
                        switch (backslashEscape, displayMath)
                        {