Пример #1
0
        public override INode Consume(Parser parser, ParseData data, Lines lines, string scope)
        {
            var current = lines.Current();

            var meta    = lines.Value().Substring(10);
            var colDefs = meta.Split(':').Select(x => int.TryParse(x, out var v) ? v : 0).ToList();
            var total   = 0;

            foreach (var d in colDefs)
            {
                if (d > 0)
                {
                    total += d;
                }
                else
                {
                    lines.SetCurrent(current);
                    return(null);
                }
            }

            if (total != 12)
            {
                lines.SetCurrent(current);
                return(null);
            }

            var i = 0;

            var arr  = new List <string>();
            var cols = new List <ColumnNode>();

            while (lines.Next() && i < colDefs.Count)
            {
                var value = lines.Value().TrimEnd();
                if (value == "%%")
                {
                    cols.Add(new ColumnNode(colDefs[i], parser.ParseElements(data, String.Join("\n", arr), scope)));
                    arr.Clear();
                    i++;
                }
                else
                {
                    arr.Add(value);
                }
                if (i >= colDefs.Count)
                {
                    break;
                }
            }

            if (i != colDefs.Count || arr.Count > 0)
            {
                lines.SetCurrent(current);
                return(null);
            }

            return(new HtmlNode("<div class=\"row\">", new NodeCollection(cols), "</div>"));
        }
Пример #2
0
        public override INode Consume(Parser parser, ParseData data, Lines lines, string scope)
        {
            var current = lines.Current();

            var line = lines.Value().Trim();
            var res  = Regex.Match(line, @"\[ref=([a-z ]+)\]", RegexOptions.IgnoreCase);

            if (!res.Success)
            {
                lines.SetCurrent(current);
                return(null);
            }

            var name  = res.Groups[1].Value;
            var arr   = new List <string>();
            var found = false;

            while (lines.Next())
            {
                var value = lines.Value().TrimEnd();
                if (value == "[/ref]")
                {
                    found = true;
                    break;
                }
                else
                {
                    arr.Add(value);
                }
            }

            if (!found || arr.Count == 0)
            {
                lines.SetCurrent(current);
                return(null);
            }

            // Trim blank lines from the start and end of the array
            for (var i = 0; i < 2; i++)
            {
                while (arr.Count > 0 && arr[0].Trim() == "")
                {
                    arr.RemoveAt(0);
                }
                arr.Reverse();
            }

            // Store the ref node
            var node = parser.ParseElements(data, string.Join("\n", arr), scope);

            data.Set($"Ref::{name}", node);

            // Return nothing
            return(PlainTextNode.Empty);
        }
Пример #3
0
        public override INode Consume(Parser parser, ParseData data, Lines lines, string scope)
        {
            var current   = lines.Current();
            var firstLine = lines.Value().Substring(3).TrimEnd();

            string lang = null;

            if (AllowedLanguages.Contains(firstLine, StringComparer.InvariantCultureIgnoreCase))
            {
                lang      = firstLine;
                firstLine = "";
            }

            var arr = new List <string> {
                firstLine
            };

            var found = false;

            while (lines.Next())
            {
                var value = lines.Value().TrimEnd();
                if (value.EndsWith("```"))
                {
                    var lastLine = value.Substring(0, value.Length - 3);
                    arr.Add(lastLine);
                    found = true;
                    break;
                }
                else
                {
                    arr.Add(value);
                }
            }

            if (!found)
            {
                lines.SetCurrent(current);
                return(null);
            }

            // Trim blank lines from the start and end of the array
            for (var i = 0; i < 2; i++)
            {
                while (arr.Count > 0 && arr[0].Trim() == "")
                {
                    arr.RemoveAt(0);
                }
                arr.Reverse();
            }

            // Replace all tabs with 4 spaces
            arr = arr.Select(x => x.Replace("\t", "    ")).ToList();

            // Find the longest common whitespace amongst all lines (ignore blank lines)
            var longestWhitespace = arr.Aggregate(9999, (c, i) =>
            {
                if (i.Trim().Length == 0)
                {
                    return(c);
                }
                var wht = i.Length - i.TrimStart().Length;
                return(Math.Min(wht, c));
            });

            // Dedent all lines by the longest common whitespace
            arr = arr.Select(a => a.Substring(Math.Min(longestWhitespace, a.Length))).ToList();

            var plain  = new UnprocessablePlainTextNode(String.Join("\n", arr));
            var cls    = string.IsNullOrWhiteSpace(lang) ? "" : $" class=\"lang-{lang}\"";
            var before = $"<pre{cls}><code>";
            var after  = "</code></pre>";

            return(new HtmlNode(before, plain, after));
        }
        public override INode Consume(Parser parser, ParseData data, Lines lines, string scope)
        {
            var current = lines.Current();

            var meta  = lines.Value().Substring(3);
            var title = "";

            var found = false;
            var arr   = new List <string>();

            while (lines.Next())
            {
                var value = lines.Value().TrimEnd();
                if (value == "~~~")
                {
                    found = true;
                    break;
                }

                if (value.Length > 1 && value[0] == ':')
                {
                    title = value.Substring(1).Trim();
                }
                else
                {
                    arr.Add(value);
                }
            }

            if (!found)
            {
                lines.SetCurrent(current);
                return(null);
            }

            string cls;

            if (meta == "message")
            {
                cls = "card-success";
            }
            else if (meta == "info")
            {
                cls = "card-info";
            }
            else if (meta == "warning")
            {
                cls = "card-warning";
            }
            else if (meta == "error")
            {
                cls = "card-danger";
            }
            else
            {
                cls = "card-default";
            }

            var before = $"<div class=\"embed-panel card {cls}\">" +
                         (title != "" ? $"<div class=\"card-header\">{System.Web.HttpUtility.HtmlEncode(title)}</div>" : "") +
                         "<div class=\"card-body\">";
            var content = parser.ParseElements(data, string.Join("\n", arr), scope);
            var after   = "</div></div>";

            return(new HtmlNode(before, content, after)
            {
                PlainBefore = title == "" ? "" : title + "\n" + new string('-', title.Length) + "\n"
            });
        }
Пример #5
0
        public override INode Consume(Parser parser, ParseData data, Lines lines, string scope)
        {
            var current = lines.Current();
            var arr     = new List <string>();

            var line = lines.Value().Trim();
            var res  = Regex.Match(line, @"\[pre(?:=([a-z ]+))?\]", RegexOptions.IgnoreCase);

            if (!res.Success)
            {
                lines.SetCurrent(current);
                return(null);
            }

            line = line.Substring(0, res.Value.Length);
            string lang = null;
            var    hl   = false;

            if (res.Groups[1].Success)
            {
                var spl = res.Groups[1].Value.Split(' ');
                hl   = spl.Contains("highlight");
                lang = spl.FirstOrDefault(x => x != "highlight");
            }

            if (line.EndsWith("[/pre]"))
            {
                lines.Next();
                arr.Add(line.Substring(0, line.Length - 6));
            }
            else
            {
                var found = false;
                while (lines.Next())
                {
                    var value = lines.Value().TrimEnd();
                    if (value.EndsWith("[/pre]"))
                    {
                        var lastLine = value.Substring(0, value.Length - 6);
                        arr.Add(lastLine);
                        found = true;
                        break;
                    }
                    else
                    {
                        arr.Add(value);
                    }
                }

                if (!found)
                {
                    lines.SetCurrent(current);
                    return(null);
                }
            }

            // Trim blank lines from the start and end of the array
            for (var i = 0; i < 2; i++)
            {
                while (arr.Count > 0 && arr[0].Trim() == "")
                {
                    arr.RemoveAt(0);
                }
                arr.Reverse();
            }

            // Process highlight commands
            var highlight = new List <(int firstLine, int numLines, string color)>();

            if (hl)
            {
                // Highlight commands get their own line so we need to keep track of which lines we're removing as we go
                var newArr    = new List <string>();
                var firstLine = 0;
                foreach (var srcLine in arr)
                {
                    if (srcLine.StartsWith("@@"))
                    {
                        var match = Regex.Match(srcLine, @"^@@(?:(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z]+|\d+)(?::(\d+))?)?$", RegexOptions.IgnoreCase | RegexOptions.Multiline);
                        if (match.Success)
                        {
                            var numLines = 1;
                            var color    = "#FF8000";
                            for (var i = 1; i < match.Groups.Count; i++)
                            {
                                var p = match.Groups[i].Value;
                                if (Colours.IsValidColor(p))
                                {
                                    color = p;
                                }
                                else if (int.TryParse(p, out var iv))
                                {
                                    numLines = iv;
                                }
                            }
                            highlight.Add((firstLine, numLines, color));
                            continue;
                        }
                    }
                    firstLine++;
                    newArr.Add(srcLine);
                }
                arr = newArr;

                // Make sure highlights don't overlap each other or go past the end of the block
                highlight.Add((arr.Count, 0, ""));
                for (var i = 0; i < highlight.Count - 1; i++)
                {
                    var(currFirst, currNum, currCol) = highlight[i];
                    var(nextFirst, _, _)             = highlight[i + 1];
                    var lastLine = currFirst + currNum - 1;
                    if (lastLine >= nextFirst)
                    {
                        highlight[i] = (currFirst, nextFirst - currFirst, currCol);
                    }
                }
                highlight.RemoveAll(x => x.numLines <= 0);
            }

            // Replace all tabs with 4 spaces
            arr = arr.Select(x => x.Replace("\t", "    ")).ToList();

            // Find the longest common whitespace amongst all lines (ignore blank lines)
            var longestWhitespace = arr.Aggregate(9999, (c, i) =>
            {
                if (i.Trim().Length == 0)
                {
                    return(c);
                }
                var wht = i.Length - i.TrimStart().Length;
                return(Math.Min(wht, c));
            });

            // Dedent all lines by the longest common whitespace
            arr = arr.Select(a => a.Substring(Math.Min(longestWhitespace, a.Length))).ToList();

            var highlights = string.Join("", highlight.Select(
                                             h => $"<div class=\"line-highlight\" style=\"top: {h.firstLine}em; height: {h.numLines}em; background: {h.color};\"></div>")
                                         );
            var plain  = new UnprocessablePlainTextNode(String.Join("\n", arr));
            var cls    = string.IsNullOrWhiteSpace(lang) ? "" : $" class=\"lang-{lang}\"";
            var before = $"<pre{cls}><code>{highlights}";
            var after  = "</code></pre>";

            return(new HtmlNode(before, plain, after));
        }