public override void InternalParse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { var match = PatternMatcher.Title.Match(reader.Line); if (!match.Success) { throw new ArgumentException("not a block title"); } var title = new Title(match.Groups["title"].Value); if (attributes != null) { attributes.Add(title); } else { attributes = new AttributeList { title } }; reader.ReadLine(); } }
public static bool ContainBlockName(this AttributeList attributes, string blockName) { if (attributes == null || attributes.Count == 0) { return(false); } return(attributes.Any(a => a.Name.Equals(blockName))); }
public static bool ContainBlockName(this AttributeList attributes, string[] blockNames) { if (attributes == null || attributes.Count == 0) { return(false); } return(attributes.Any(a => blockNames.Contains(a.Name, StringComparer.OrdinalIgnoreCase))); }
public override void InternalParse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { var match = PatternMatcher.Include.Match(reader.Line); if (!match.Success) { throw new ArgumentException("not an include"); } var include = new Include(match.Groups["path"].Value); var attributesValue = match.Groups["attributes"].Value; if (!string.IsNullOrEmpty(attributesValue)) { var attributeValues = SplitOnCharacterOutsideQuotes(attributesValue); foreach (var attributeValue in attributeValues) { var attributeMatch = PatternMatcher.AttributeNameValue.Match(attributeValue); if (attributeMatch.Success) { switch (attributeMatch.Groups["name"].Value.ToLowerInvariant()) { case "leveloffset": if (int.TryParse(attributeMatch.Groups["value"].Value, out var offset)) { include.LevelOffset = offset; } break; case "lines": include.Lines = attributeMatch.Groups["value"].Value; break; case "tag": case "tags": include.Tags = attributeMatch.Groups["value"].Value; break; case "indent": if (int.TryParse(attributeMatch.Groups["value"].Value, out var indent)) { include.Indent = indent; } break; default: throw new NotImplementedException("TODO: add attribute to include attribute list"); } } } } container.Add(include); attributes = null; reader.ReadLine(); }
public override void InternalParse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { var match = PatternMatcher.ElementAttribute.Match(reader.Line); if (!match.Success) { throw new ArgumentException("not a block attribute"); } var attributesValue = match.Groups["attributes"].Value.Trim(); if (attributes == null) { attributes = new AttributeList(); } if (attributesValue.IndexOf(",", StringComparison.Ordinal) == -1) { switch (attributesValue) { case "float": attributes.IsFloating = true; reader.ReadLine(); return; case "discrete": attributes.IsDiscrete = true; reader.ReadLine(); return; default: attributes.Add(ParseElementAttributesWithPosition(attributesValue, 0)); reader.ReadLine(); return; } } var inputs = SplitOnCharacterOutsideQuotes(attributesValue); if (inputs[0] == "quote" || inputs[0] == "verse") { for (var index = 0; index < inputs.Length; index++) { var i = inputs[index]; attributes.Add(new Attribute(i, true)); } reader.ReadLine(); return; } var attributeLists = inputs.Select(ParseElementAttributesWithPosition); attributes = attributeLists.Aggregate(attributes, (first, second) => first.Add(second)); reader.ReadLine(); }
/// <summary> /// Parses text from <see cref="IDocumentReader"/> into an <see cref="Document"/> /// </summary> /// <param name="reader">The reader.</param> /// <returns>An new instance of <see cref="Document"/></returns> public Document Parse(IDocumentReader reader) { var document = new Document(reader.Path); var buffer = new List <string>(8); AttributeList attributes = null; Parse(document, reader, null, ref buffer, ref attributes); return(document); }
public override void InternalParse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { var comment = new Comment(reader.Line.Substring(2)); container.Add(comment); reader.ReadLine(); }
protected void ProcessBuffer(Container container, ref List <string> buffer, ref AttributeList attributes) { if (buffer.Count > 0) { if (attributes.ContainBlockName("quote")) { ProcessLine <Quote>(container, ref buffer, ref attributes); } else if (attributes.ContainBlockName("pass")) { ProcessSimple <Passthrough>(container, ref buffer, ref attributes); } else if (attributes.ContainBlockName("example")) { ProcessLine <Example>(container, ref buffer, ref attributes); } else if (attributes.ContainBlockName("stem")) { ProcessSimple <Stem>(container, ref buffer, ref attributes); } else if (attributes.ContainBlockName("sidebar")) { ProcessLine <Sidebar>(container, ref buffer, ref attributes); } else if (attributes.ContainBlockName("source")) { ProcessSimple <Source>(container, ref buffer, ref attributes); } else if (attributes.ContainBlockName("listing")) { ProcessSimple <Listing>(container, ref buffer, ref attributes); } else if (attributes.ContainBlockName("literal")) { ProcessSimple <Literal>(container, ref buffer, ref attributes); } else if (attributes.ContainBlockName("comment")) { ProcessSimple <Comment>(container, ref buffer, ref attributes); } else if (attributes.ContainBlockName("verse")) { ProcessLine <Verse>(container, ref buffer, ref attributes); } else { ProcessParagraph(container, ref buffer, ref attributes); } buffer = new List <string>(8); } attributes = null; }
protected void ProcessParagraph(Container parent, ref List <string> buffer, ref AttributeList attributes) { if (buffer.Count > 0 && !buffer.All(string.IsNullOrWhiteSpace)) { var inlineElements = ProcessInlineElements(string.Join(Environment.NewLine, buffer)); var paragraph = new Paragraph(inlineElements); paragraph.Attributes.Add(attributes); parent.Add(paragraph); attributes = null; buffer = new List <string>(8); } }
public override void InternalParse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { var listingRegex = PatternMatcher.GetDelimiterRegexFor <TElement>(); var isDelimiter = listingRegex.IsMatch(reader.Line); if (isDelimiter) { ProcessParagraph(container, ref buffer); reader.ReadLine(); while (reader.Line != null && !listingRegex.IsMatch(reader.Line)) { buffer.Add(reader.Line); reader.ReadLine(); } } else { buffer.Add(reader.Line); reader.ReadLine(); while (reader.Line != null && !PatternMatcher.BlankCharacters.IsMatch(reader.Line)) { buffer.Add(reader.Line); reader.ReadLine(); } } var element = new TElement { Text = string.Join(Environment.NewLine, buffer) }; element.Attributes.Add(attributes); reader.ReadLine(); if (isDelimiter) { while (reader.Line != null && PatternMatcher.Callout.IsMatch(reader.Line)) { ParseCallout(element, reader.Line); reader.ReadLine(); } } container.Add(element); attributes = null; buffer = new List <string>(8); }
public void Parse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { var document = (Document)container; ParseDocumentTitle(document, reader, ref attributes); reader.ReadLine(); if (reader.Line == null) { return; } ParseAuthors(document, reader.Line); reader.ReadLine(); }
/// <summary> /// Visits the attribute list. /// </summary> /// <param name="attributes">The attributes.</param> public virtual void VisitAttributeList(AttributeList attributes) { if (attributes == null) { return; } if (attributes.HasAnchor) { attributes.Anchor.Accept(this); } if (attributes.IsDiscrete) { _writer.WriteLine("[discrete]"); } else if (attributes.IsFloating) { _writer.WriteLine("[float]"); } if (attributes.Any()) { _writer.Write("["); for (int index = 0; index < attributes.Count; index++) { var lastAttribute = index == attributes.Count - 1; var asciiAttribute = attributes[index]; asciiAttribute.Accept(this); if (!lastAttribute) { _writer.Write(","); } } _writer.WriteLine("]"); } if (attributes.HasTitle) { attributes.Title.Accept(this); } }
// TODO: based on html output, a section title should define a section block element into which all proceeding elements should be added, until the next section Title is hit public override void InternalParse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { var match = PatternMatcher.SectionTitle.Match(reader.Line); if (!match.Success) { throw new ArgumentException("not a section title"); } var title = match.Groups["title"].Value; var inlineElements = ProcessInlineElements(title); var level = match.Groups["level"].Value.Length; var sectionTitle = new SectionTitle(inlineElements, level); sectionTitle.Attributes.Add(attributes); container.Add(sectionTitle); attributes = null; reader.ReadLine(); }
protected void DescendingParse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { while (reader.Line != null) { if (predicate != null && predicate(reader.Line)) { ProcessParagraph(container, ref buffer, ref attributes); return; } var parsed = false; for (var index = 0; index < Parsers.Length; index++) { var parser = Parsers[index]; if (parser.IsMatch(reader, container, attributes)) { parser.Parse(container, reader, predicate, ref buffer, ref attributes); parsed = true; break; } } if (!parsed) { if (PatternMatcher.BlankCharacters.IsMatch(reader.Line)) { ProcessBuffer(container, ref buffer, ref attributes); } else { buffer.Add(reader.Line); } reader.ReadLine(); } } ProcessBuffer(container, ref buffer, ref attributes); }
/// <summary> /// Visits the attribute list. /// </summary> /// <param name="attributes">The attributes.</param> public virtual void VisitAttributeList(AttributeList attributes) { if (attributes == null) { return; } if (attributes.HasAnchor) { attributes.Anchor.Accept(this); } if (attributes.HasTitle) { attributes.Title.Accept(this); } foreach (var attribute in attributes) { attribute.Accept(this); } }
public override void InternalParse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { var attributeEntry = ParseAttributeEntry(reader.Line); var document = container as Document; if (document != null) { if (document.Count == 0) { document.Attributes.Add(attributeEntry); } else { document.Add(attributeEntry); } } else { container.Add(attributeEntry); } reader.ReadLine(); }
public override void Parse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { var delimiterRegex = PatternMatcher.GetDelimiterRegexFor <TElement>(); var element = new TElement(); element.Attributes.Add(attributes); if (delimiterRegex.IsMatch(reader.Line)) { ProcessParagraph(container, ref buffer); reader.ReadLine(); Parse(element, reader, delimiterRegex); } else { ProcessParagraph(element, ref buffer); Parse(element, reader, PatternMatcher.BlankCharacters); } container.Add(element); attributes = null; reader.ReadLine(); }
public override void InternalParse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { var match = PatternMatcher.OrderedListItem.Match(reader.Line); if (!match.Success) { throw new ArgumentException("not an ordered list item"); } var level = match.Groups["level"].Value; var orderedListItem = new OrderedListItem(level.Length); orderedListItem.Attributes.Add(attributes); var number = match.Groups["number"].Value; var upperAlpha = match.Groups["upperalpha"].Value; var lowerAlpha = match.Groups["loweralpha"].Value; var upperRoman = match.Groups["upperRoman"].Value; var lowerRoman = match.Groups["lowerRoman"].Value; if (!string.IsNullOrEmpty(number)) { orderedListItem.Number = int.Parse(number); } else if (!string.IsNullOrEmpty(upperAlpha)) { orderedListItem.Numbering = NumberStyle.UpperAlpha; orderedListItem.Number = Array.IndexOf(Patterns.UpperAlphabet, upperAlpha) + 1; } else if (!string.IsNullOrEmpty(lowerAlpha)) { orderedListItem.Numbering = NumberStyle.LowerAlpha; orderedListItem.Number = Array.IndexOf(Patterns.LowerAlphabet, lowerAlpha) + 1; } else if (!string.IsNullOrEmpty(upperRoman)) { orderedListItem.Numbering = NumberStyle.UpperRoman; orderedListItem.Number = RomanNumerals.ToInt(upperRoman); } else if (!string.IsNullOrEmpty(lowerRoman)) { orderedListItem.Numbering = NumberStyle.LowerRoman; orderedListItem.Number = RomanNumerals.ToInt(lowerRoman); } var text = match.Groups["text"].Value; buffer.Add(text); reader.ReadLine(); attributes = null; while (reader.Line != null && !PatternMatcher.BlankCharacters.IsMatch(reader.Line) && !PatternMatcher.OrderedListItem.IsMatch(reader.Line) && (predicate == null || !predicate(reader.Line))) { if (PatternMatcher.ListItemContinuation.IsMatch(reader.Line)) { ProcessBuffer(orderedListItem, ref buffer, ref attributes); reader.ReadLine(); DescendingParse( orderedListItem, reader, line => PatternMatcher.BlankCharacters.IsMatch(line) || PatternMatcher.OrderedListItem.IsMatch(line), ref buffer, ref attributes); } else { buffer.Add(reader.Line); reader.ReadLine(); } } ProcessBuffer(orderedListItem, ref buffer, ref attributes); OrderedList orderedList; if (container.Count > 0) { orderedList = container[container.Count - 1] as OrderedList; if (orderedList != null && orderedList.Items.Count > 0 && orderedList.Items[0].Level == orderedListItem.Level) { orderedList.Items.Add(orderedListItem); } else { orderedList = new OrderedList { Items = { orderedListItem } }; container.Add(orderedList); } } else { orderedList = new OrderedList { Items = { orderedListItem } }; container.Add(orderedList); } attributes = null; }
public virtual void Visit(AttributeList attributes) { }
public override bool IsMatch(IDocumentReader reader, Container container, AttributeList attributes) => PatternMatcher.CheckListItem.IsMatch(reader.Line);
public override void InternalParse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { var match = PatternMatcher.CheckListItem.Match(reader.Line); if (!match.Success) { throw new ArgumentException("not a check list item"); } var level = match.Groups["level"].Value; var isChecked = !string.IsNullOrWhiteSpace(match.Groups["checked"].Value); var text = match.Groups["text"].Value; var listItem = new CheckListItem(level.Length, isChecked); listItem.Attributes.Add(attributes); buffer.Add(text); reader.ReadLine(); attributes = null; while (reader.Line != null && !PatternMatcher.ListItemContinuation.IsMatch(reader.Line) && !PatternMatcher.BlankCharacters.IsMatch(reader.Line) && !PatternMatcher.CheckListItem.IsMatch(reader.Line) && !PatternMatcher.ListItem.IsMatch(reader.Line) && (predicate == null || !predicate(reader.Line))) { if (PatternMatcher.ListItemContinuation.IsMatch(reader.Line)) { ProcessBuffer(listItem, ref buffer, ref attributes); reader.ReadLine(); DescendingParse( listItem, reader, line => PatternMatcher.BlankCharacters.IsMatch(line) || PatternMatcher.ListItem.IsMatch(line) || PatternMatcher.CheckListItem.IsMatch(reader.Line), ref buffer, ref attributes); } else { buffer.Add(reader.Line); reader.ReadLine(); } } ProcessBuffer(listItem, ref buffer, ref attributes); UnorderedList unorderedList; if (container.Count > 0) { unorderedList = container[container.Count - 1] as UnorderedList; if (unorderedList != null && unorderedList.Items.Count > 0 && unorderedList.Items[0].Level == listItem.Level) { unorderedList.Items.Add(listItem); } else { unorderedList = new UnorderedList { Items = { listItem } }; container.Add(unorderedList); } } else { unorderedList = new UnorderedList { Items = { listItem } }; container.Add(unorderedList); } attributes = null; }
public override void InternalParse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { var match = PatternMatcher.LabeledListItem.Match(reader.Line); if (!match.Success) { throw new ArgumentException("not a labeled list item"); } var label = match.Groups["label"].Value; var level = match.Groups["level"].Value.Length; // levels start at 0 if (level > 0) { level -= 2; } var labeledListItem = new LabeledListItem(label, level); labeledListItem.Attributes.Add(attributes); attributes = null; var text = match.Groups["text"].Value; // labeled lists are lenient with whitespace so can have whitespace after the label // and before any content. if (!string.IsNullOrWhiteSpace(text)) { buffer.Add(text); reader.ReadLine(); } else { reader.ReadLine(); while (reader.Line != null && PatternMatcher.BlankCharacters.IsMatch(reader.Line)) { reader.ReadLine(); } } while (reader.Line != null && !PatternMatcher.BlankCharacters.IsMatch(reader.Line) && !PatternMatcher.LabeledListItem.IsMatch(reader.Line) && (predicate == null || !predicate(reader.Line))) { if (PatternMatcher.ListItemContinuation.IsMatch(reader.Line)) { ProcessBuffer(labeledListItem, ref buffer, ref attributes); reader.ReadLine(); DescendingParse( labeledListItem, reader, line => PatternMatcher.BlankCharacters.IsMatch(line) || PatternMatcher.LabeledListItem.IsMatch(line), ref buffer, ref attributes); } else { buffer.Add(reader.Line); reader.ReadLine(); } } ProcessBuffer(labeledListItem, ref buffer, ref attributes); LabeledList labeledList; if (container.Count > 0) { labeledList = container[container.Count - 1] as LabeledList; if (labeledList != null && labeledList.Items.Count > 0 && labeledList.Items[0].Level == labeledListItem.Level) { labeledList.Items.Add(labeledListItem); } else { labeledList = new LabeledList { Items = { labeledListItem } }; container.Add(labeledList); } } else { labeledList = new LabeledList { Items = { labeledListItem } }; container.Add(labeledList); } attributes = null; }
public bool IsMatch(IDocumentReader reader, Container container, AttributeList attributes) => PatternMatcher.DocumentTitle.IsMatch(reader.Line) && (reader.LineNumber == 1 || container.GetType() == typeof(Document) && container.All(e => e is Comment));
private static void ParseDocumentTitle(Document document, IDocumentReader reader, ref AttributeList attributes) { var match = PatternMatcher.DocumentTitle.Match(reader.Line); if (!match.Success) { throw new ArgumentException("not a document title"); } var title = match.Groups["title"].Value; var lastColonIndex = title.LastIndexOf(":", StringComparison.OrdinalIgnoreCase); var documentTitle = lastColonIndex > -1 ? new DocumentTitle(title.Substring(0, lastColonIndex), title.Substring(lastColonIndex + 1)) : new DocumentTitle(title); documentTitle.Attributes.Add(attributes); document.Title = documentTitle; attributes = null; }
public abstract bool IsMatch(IDocumentReader reader, Container container, AttributeList attributes);
public bool IsMatch(IDocumentReader reader, Container container, AttributeList attributes) => PatternMatcher.Anchor.IsMatch(reader.Line);
public override void InternalParse(Container container, IDocumentReader reader, Func <string, bool> predicate, ref List <string> buffer, ref AttributeList attributes) { throw new NotImplementedException("TODO"); }
private static AttributeList ParseElementAttributesWithPosition(string input, int position) { var attributes = new AttributeList(); input = input.Trim(); var start = 0; for (var index = 0; index < input.Length; index++) { var currentChar = input[index]; var last = index == input.Length - 1; if (currentChar == '%') { var options = new List <string>(); var optionsStartIndex = index + 1; for (int i = optionsStartIndex; i < input.Length; i++) { var lastChar = i == input.Length - 1; if (input[i] == '%') { options.Add(input.Substring(optionsStartIndex, i - optionsStartIndex)); optionsStartIndex = i + 1; } else if (lastChar || input[i] == '#' || input[i] == '.' || input[i] == '=') { options.Add(lastChar ? input.Substring(optionsStartIndex, i - (optionsStartIndex - 1)) : input.Substring(optionsStartIndex, i - 1)); attributes.Add(new OptionsAttribute(options.ToArray(), false)); index = i; start = i; break; } } } else if (currentChar == '#') { var startIdIndex = index + 1; for (var i = startIdIndex; i < input.Length; i++) { var lastChar = i == input.Length - 1; if (lastChar) { var value = input.Substring(startIdIndex); attributes.Add(new IdAttribute(value, false)); index = i; start = i; break; } if (input[i] == '.' || input[i] == '%' || input[i] == '=') { var value = input.Substring(startIdIndex, i - 1); attributes.Add(new IdAttribute(value, false)); index = i - 1; start = i - 1; break; } } } else if (currentChar == '.') { var options = new List <string>(); var roleStartIndex = index + 1; for (var i = roleStartIndex; i < input.Length; i++) { var lastChar = i == input.Length - 1; if (input[i] == '.') { options.Add(input.Substring(roleStartIndex, i - roleStartIndex)); roleStartIndex = i + 1; } else if (lastChar || input[i] == '#' || input[i] == '%' || input[i] == '=') { options.Add(lastChar ? input.Substring(roleStartIndex, i - (roleStartIndex - 1)) : input.Substring(roleStartIndex, i - 1)); attributes.Add(new RoleAttribute(options, false)); index = i; start = i; break; } } } else if (currentChar == '=') { var name = input.Substring(start, index); for (int i = index + 1; i < input.Length; i++) { var lastChar = i == input.Length - 1; if (lastChar || input[i] == '#' || input[i] == '%' || input[i] == '.') { var singleQuoted = input[index + 1] == '\''; var value = singleQuoted || input[index + 1] == '"' ? input.Substring(index + 2, i - (name.Length + 2)) : input.Substring(index + 1, i - name.Length); // TODO: handle known named elements switch (name.ToLowerInvariant()) { case "id": if (value.IndexOf(",", StringComparison.OrdinalIgnoreCase) > -1) { var valueParts = value.Split(','); attributes.Add(new IdAttribute(valueParts[0], valueParts[1], singleQuoted)); } else { attributes.Add(new IdAttribute(value, singleQuoted)); } break; case "role": attributes.Add(new RoleAttribute(value, singleQuoted)); break; case "options": case "opts": attributes.Add(new OptionsAttribute(value, singleQuoted)); break; case "subs": attributes.Add(new SubstitutionsAttribute(value)); break; default: attributes.Add(new NamedAttribute(name, value, singleQuoted)); break; } index = i; start = i; break; } } } else if (index == 0 && position == 0) { var hashIndex = input.IndexOf("#", StringComparison.OrdinalIgnoreCase); var dotIndex = input.IndexOf(".", StringComparison.OrdinalIgnoreCase); var percentIndex = input.IndexOf("%", StringComparison.OrdinalIgnoreCase); if (hashIndex > -1 || dotIndex > -1 || percentIndex > -1) { var minIndex = new[] { hashIndex, dotIndex, percentIndex }.Where(i => i != -1).Min(); if (minIndex > 1) { var name = input.Substring(0, minIndex); attributes.Add(new Attribute(name)); index = minIndex - 1; start = minIndex - 1; } } } else if (last) { var name = input.Substring(start); attributes.Add(new Attribute(name)); } } return(attributes); }
public override bool IsMatch(IDocumentReader reader, Container container, AttributeList attrtibutes) => PatternMatcher.SectionTitle.IsMatch(reader.Line);
/// <summary> /// Determines whether the specified <see cref="AttributeList" />, is equal to this instance. /// </summary> /// <param name="other">The other.</param> /// <returns>true if equal; otherwise, false</returns> protected bool Equals(AttributeList other) => Equals(Anchor, other.Anchor) && Equals(Title, other.Title) && AttributesEqual(_attributes, other._attributes);