예제 #1
0
        public void TestEggsML()
        {
            var expectations = new List <Tuple <string, string, string> >
            {
                Tuple.Create("", "(0:)", ""),
                Tuple.Create("*bold*", "(1:*(1:))", "*bold*"),
                Tuple.Create("non-bold *bold* non-bold", "(3:,*(1:),)", "non-bold *bold* non-bold"),
                Tuple.Create("more ***bold*", "(2:,*(1:))", "more *bold*"),
                Tuple.Create("Nested |*tags*|", "(2:,|(1:*(1:)))", "Nested |*tags*|"),
                Tuple.Create("Nested |`|||tags|`| yeah!", "(3:,|(1:|(1:)),)", "Nested |`|||tags|`| yeah!"),
                Tuple.Create("Empty |`| tag!", "(3:,|(0:),)", "Empty |`| tag!"),
                Tuple.Create(@"Escaped ""http://www.google.com/"" URL", "(1:)", @"""Escaped http://www.google.com/ URL"""),
                Tuple.Create(@"""String """"string"""" string""", "(1:)", @"String """"string"""" string"),
                Tuple.Create("[[square]] [<[tag]>]", "(2:,[(1:<(1:[(1:))))", "[[square]] [<[tag]>]"),
            };

            foreach (var tuple in expectations)
            {
                Func <EggsNode, string> recurse = null;
                recurse = node => (node is EggsTag ? ((EggsTag)node).Tag + "(" + ((EggsTag)node).Children.Count.ToString() + ":" + ((EggsTag)node).Children.Select(n => recurse(n)).JoinString(",") + ")" : "");
                var eggs = EggsML.Parse(tuple.Item1);
                Assert.AreEqual(tuple.Item2, recurse(eggs));
                Assert.AreEqual(tuple.Item3, eggs.ToString());
            }

            Assert.Throws <ArgumentNullException>(() => EggsML.Parse(null));
            Assert.Throws <EggsMLParseException>(() => EggsML.Parse("xyz] xyz"));
            Assert.Throws <EggsMLParseException>(() => EggsML.Parse("xyz [[[xyz"));
            Assert.Throws <EggsMLParseException>(() => EggsML.Parse("xyz```xyz"));
            Assert.Throws <EggsMLParseException>(() => EggsML.Parse("xyz*****xyz"));
            Assert.Throws <EggsMLParseException>(() => EggsML.Parse("xyz]]] xyz"));
            Assert.Throws <EggsMLParseException>(() => EggsML.Parse("xyz *xyz"));
        }
예제 #2
0
        /// <summary>Logs a message to the console.</summary>
        public override void Log(uint verbosity, LogType type, string message)
        {
            if (message == null)
            {
                message = "<null>";
            }
            lock (this)
            {
                if (VerbosityLimit[type] < verbosity)
                {
                    return;
                }

                string fmtInfo, indent;
                GetFormattedStrings(out fmtInfo, out indent, verbosity, type);

                var prevCol = Console.ForegroundColor;
                var col     = GetMessageTypeColor(type);

                TextWriter consoleStream = (type == LogType.Error && ErrorsToStdErr) ? Console.Error : Console.Out;
                int        wrapWidth     = WordWrap ? ConsoleUtil.WrapToWidth() : int.MaxValue;
                bool       first         = true;
                if (InterpretMessagesAsEggsML)
                {
                    foreach (var line in EggsML.Parse(message).ToConsoleColoredStringWordWrap(wrapWidth - fmtInfo.Length))
                    {
                        Console.ForegroundColor = col;
                        consoleStream.Write(first ? fmtInfo : indent);
                        first = false;
                        ConsoleUtil.WriteLine(line, type == LogType.Error && ErrorsToStdErr);
                    }
                }
                else
                {
                    Console.ForegroundColor = col;
                    foreach (var line in message.WordWrap(wrapWidth - fmtInfo.Length))
                    {
                        consoleStream.Write(first ? fmtInfo : indent);
                        first = false;
                        consoleStream.WriteLine(line);
                    }
                }

                if (first)
                {
                    Console.ForegroundColor = col;
                    consoleStream.WriteLine(fmtInfo); // don't completely skip blank messages
                }

                Console.ForegroundColor = prevCol;
            }
        }
예제 #3
0
        /// <summary>
        ///     Generates a sequence of <see cref="ConsoleColoredString"/>s from an EggsML parse tree by word-wrapping the
        ///     output at a specified character width.</summary>
        /// <param name="wrapWidth">
        ///     The number of characters at which to word-wrap the output.</param>
        /// <param name="hangingIndent">
        ///     The number of spaces to add to each line except the first of each paragraph, thus creating a hanging
        ///     indentation.</param>
        /// <returns>
        ///     The sequence of <see cref="ConsoleColoredString"/>s generated from the EggsML parse tree.</returns>
        /// <remarks>
        ///     <para>
        ///         The following EggsML tags map to the following console colors:</para>
        ///     <list type="bullet">
        ///         <item><description>
        ///             <c>~</c> = black, or dark gray if inside a <c>*</c> tag</description></item>
        ///         <item><description>
        ///             <c>/</c> = dark blue, or blue if inside a <c>*</c> tag</description></item>
        ///         <item><description>
        ///             <c>$</c> = dark green, or green if inside a <c>*</c> tag</description></item>
        ///         <item><description>
        ///             <c>&amp;</c> = dark cyan, or cyan if inside a <c>*</c> tag</description></item>
        ///         <item><description>
        ///             <c>_</c> = dark red, or red if inside a <c>*</c> tag</description></item>
        ///         <item><description>
        ///             <c>%</c> = dark magenta, or magenta if inside a <c>*</c> tag</description></item>
        ///         <item><description>
        ///             <c>^</c> = dark yellow, or yellow if inside a <c>*</c> tag</description></item>
        ///         <item><description>
        ///             <c>=</c> = dark gray (independent of <c>*</c> tag)</description></item></list>
        ///     <para>
        ///         Text which is not inside any of the above color tags defaults to light gray, or white if inside a <c>*</c>
        ///         tag.</para>
        ///     <para>
        ///         Additionally, the <c>+</c> tag can be used to suppress word-wrapping within a certain stretch of text. In
        ///         other words, the contents of a <c>+</c> tag are treated as if they were a single word. Use this in
        ///         preference to U+00A0 (no-break space) as it is more explicit and more future-compatible in case
        ///         hyphenation is ever implemented here.</para></remarks>
        public IEnumerable <ConsoleColoredString> ToConsoleColoredStringWordWrap(int wrapWidth, int hangingIndent = 0)
        {
            var results = new List <ConsoleColoredString> {
                ConsoleColoredString.Empty
            };

            EggsML.WordWrap(this, ConsoleColor.Gray, wrapWidth,
                            (color, text) => text.Length,
                            (color, text, width) => { results[results.Count - 1] += new ConsoleColoredString(text, color); },
                            (color, newParagraph, indent) =>
            {
                var s = newParagraph ? 0 : indent + hangingIndent;
                results.Add(new ConsoleColoredString(new string(' ', s), color));
                return(s);
            },
                            (color, tag, parameter) =>
            {
                bool curLight = color >= ConsoleColor.DarkGray;
                switch (tag)
                {
                case '~': color = curLight ? ConsoleColor.DarkGray : ConsoleColor.Black; break;

                case '/': color = curLight ? ConsoleColor.Blue : ConsoleColor.DarkBlue; break;

                case '$': color = curLight ? ConsoleColor.Green : ConsoleColor.DarkGreen; break;

                case '&': color = curLight ? ConsoleColor.Cyan : ConsoleColor.DarkCyan; break;

                case '_': color = curLight ? ConsoleColor.Red : ConsoleColor.DarkRed; break;

                case '%': color = curLight ? ConsoleColor.Magenta : ConsoleColor.DarkMagenta; break;

                case '^': color = curLight ? ConsoleColor.Yellow : ConsoleColor.DarkYellow; break;

                case '=': color = ConsoleColor.DarkGray; break;

                case '*': color = curLight ? color : (ConsoleColor)((int)color + 8); break;
                }
                return(color, 0);
            });
            if (results.Last().Length == 0)
            {
                results.RemoveAt(results.Count - 1);
            }
            return(results);
        }
예제 #4
0
        /// <summary>
        ///     Reconstructs the original EggsML that is represented by this node.</summary>
        /// <remarks>
        ///     This does not necessarily return the same EggsML that was originally parsed. For example, redundant uses of
        ///     the <c>`</c> character are removed.</remarks>
        public override string ToString()
        {
            if (_children.Count == 0)
            {
                return(Tag == null ? "" : EggsML.alwaysOpens(Tag) ? Tag.ToString() + EggsML.opposite(Tag) : Tag + "`" + Tag);
            }

            var childrenStr = stringify(_children, Tag);

            return(Tag == null
                ? childrenStr
                : childrenStr.StartsWith(Tag)
                    ? childrenStr.EndsWith(EggsML.opposite(Tag))
                        ? Tag + "`" + childrenStr + "`" + EggsML.opposite(Tag)
                        : Tag + "`" + childrenStr + EggsML.opposite(Tag)
                    : childrenStr.EndsWith(EggsML.opposite(Tag))
                        ? Tag + childrenStr + "`" + EggsML.opposite(Tag)
                        : Tag + childrenStr + EggsML.opposite(Tag));
        }
예제 #5
0
        /// <summary>
        ///     Turns a list of child nodes into EggsML mark-up.</summary>
        /// <param name="children">
        ///     List of children to turn into mark-up.</param>
        /// <param name="tag">
        ///     If non-null, assumes we are directly inside a tag with the specified character, causing necessary escaping to
        ///     be performed.</param>
        /// <returns>
        ///     EggsML mark-up representing the same tree structure as this node.</returns>
        protected static string stringify(List <EggsNode> children, char?tag)
        {
            if (children == null || children.Count == 0)
            {
                return("");
            }

            var sb = new StringBuilder();

            for (int i = 0; i < children.Count; i++)
            {
                var childStr = children[i].ToString();
                if (string.IsNullOrEmpty(childStr))
                {
                    continue;
                }

                // If the item is a tag, and it is the same tag character as the current one, we need to escape it by tripling it
                if (sb.Length > 0 && childStr.Length > 0 && childStr[0] == sb[sb.Length - 1])
                {
                    sb.Append('`');
                }
                if (tag != null && children[i] is EggsTag && ((EggsTag)children[i]).Tag == tag && !EggsML.alwaysOpens(tag))
                {
                    sb.Append(new string(tag.Value, 2));
                }
                sb.Append(childStr);
            }
            return(sb.ToString());
        }