private static bool CanParseDoubleLineHeading( ParseInput input ) { bool isDoubleLineHeading = false; if (input.Lines().Count > 1) { isDoubleLineHeading = regexDoubleLineHeading.Match(input.Lines()[1]).Success; } return(isDoubleLineHeading); }
private static ParseResult ParseDoubleLineHeading( ParseInput input ) { ArraySegment <string> lines = input.Lines(); ParseResult result = new ParseResult(); int level; if (lines[1].StartsWith("=")) { level = 1; } else { level = 2; } MarkdownHeading element = new MarkdownHeading( level, MarkdownParser.ParseInnerText( new ParseInput( input, lines[0] ) ) ); lines[0] = ""; lines[1] = ""; result.Success = true; result.AddContent( element ); return(result); }
private static void RemoveListIndicators( ParseInput input ) { ArraySegment <string> lines = input.Lines(); for (int i = 0; i < lines.Count; i++) { string truncated = lines[i]; Match lineOrderedContentMatch = regexOrderedListLine.Match(lines[i]); Match lineUnorderedContentMatch = regexUnorderedListLine.Match(lines[i]); if ( lineOrderedContentMatch.Success || lineUnorderedContentMatch.Success ) { if (lineOrderedContentMatch.Success) { truncated = lineOrderedContentMatch.Groups[1].Value; } else if (lineUnorderedContentMatch.Success) { truncated = lineUnorderedContentMatch.Groups[1].Value; } int spaces = 0; // Count spaces while ( (spaces < truncated.Length) && (truncated[spaces] == ' ') ) { spaces++; } // If there are fewer than 5 spaces, remove all if (spaces < 5) { lines[i] = truncated.Substring(spaces); } else { // More than five, just remove one space lines[i] = truncated.Substring(1); } } else { lines[i] = lines[i]; } } }
private static ParseResult ParseSingleLineHeading( ParseInput input ) { ArraySegment <string> lines = input.Lines(); ParseResult result = new ParseResult(); // Calculate heading level, (maximum 6) int level = 0; while ( (level < 6) && (lines[0][level] == '#') ) { level++; } Match contentMatch = regexSingleLineHeading.Match(lines[0]); string content = StripLeadingCharacter( StripTrailingCharacter( contentMatch.Groups[1].Value, '#' ), ' ' ); lines[0] = ""; result.Success = true; result.AddContent( new MarkdownHeading( level, MarkdownParser.ParseInnerText( new ParseInput( input, content ) ) ) ); return(result); }
public static bool CanParseFrom( ParseInput input ) { ArraySegment <string> lines = input.Lines(); if (!regexBacktickSectionOpen.Match(lines[0]).Success) { return(false); } else { for (int i = 1; i < lines.Count; i++) { if (regexBacktickSectionClose.Match(lines[i]).Success) { return(true); } } } return(false); }
public static ParseResult ParseFrom( ParseInput input ) { ParseResult result = new ParseResult(); if (!CanParseFrom(input)) { return(result); } ArraySegment <string> lines = input.Lines(); lines[0] = ""; LinkedList <IHtmlable> innerContent = new LinkedList <IHtmlable>(); int i = 1; while (!regexBacktickSectionClose.Match(lines[i]).Success) { innerContent.AddLast( new MarkdownText( lines[i] ) ); lines[i] = ""; i++; } // Remember to clear final line (closing backticks) lines[i] = ""; MarkdownCodeBlock blockCodeElement = new MarkdownCodeBlock( Utils.LinkedListToArray(innerContent) ); result.Success = true; result.AddContent(blockCodeElement); return(result); }
public static ParseResult ParseFrom( ParseInput input ) { ArraySegment <string> lines = input.Lines(); ParseResult result = new ParseResult(); if (!CanParseFrom(input)) { return(result); } int endQuoteSection = FindEndOfQuoteSection( lines ); string[] truncatedLines = new string[endQuoteSection]; // Remove quote arrows and spaces, if needed for (int i = 0; i < endQuoteSection; i++) { string truncated = lines[i]; if (lines[i].StartsWith(">")) { truncated = truncated.Substring(1); int spaces = 0; // Count spaces while ( (spaces < truncated.Length) && (truncated[spaces] == ' ') ) { spaces++; } // If there are fewer than 5 spaces, remove all if (spaces < 5) { truncatedLines[i] = truncated.Substring(spaces); } else { // More than five, just remove one space truncatedLines[i] = truncated.Substring(1); } } else { truncatedLines[i] = lines[i]; } // Remove original line lines[i] = ""; } /* * The truncated lines should be parsed as any other line group * and wrapped in a blockquote element */ MarkdownParser parser = new MarkdownParser( truncatedLines ); MarkdownQuote quoteElement = new MarkdownQuote( parser.ContentAsArray() ); result.Success = true; result.AddContent( quoteElement ); return(result); }
public static ParseResult ParseFrom( ParseInput input ) { ArraySegment <string> lines = input.Lines(); ParseResult result = new ParseResult(); if (!CanParseFrom(input)) { return(result); } /* * Work out the list type from the first line * before we start to mangle the line contents */ MarkdownElementType type; if (regexOrderedListLine.Match(input.FirstLine).Success) { type = MarkdownElementType.OrderedList; } else { type = MarkdownElementType.UnorderedList; } int endListSection = FindEndOfListSection( lines ); // New array segment with only parsed content ArraySegment <string> listLines = new ArraySegment <string>( lines.Array, lines.Offset, endListSection ); // Need to split into groups per list item int currentIndex = 0; // Hold the parsed list items as we go LinkedList <IHtmlable> listItems = new LinkedList <IHtmlable>(); // Track whether list item contents should be in a paragraph bool whitespaceLineBefore = false; bool whitespaceLineAfter = false; while (currentIndex < endListSection) { int endIndex = FindEndOfListItem( listLines, currentIndex ); /* * There is a whitespace line between * this list item and the following one * and this list item isn't the final one */ whitespaceLineAfter = ( (endIndex < listLines.Count) && ( ContainsOnlyWhitespace( listLines[endIndex - 1] ) ) ); // Create new parse input for this list item ParseInput listItemLines = new ParseInput( input.Urls, listLines.Array, listLines.Offset + currentIndex, endIndex - currentIndex ); RemoveListIndicators( listItemLines ); ParseResult nextListItem = MarkdownListItem.ParseFrom( listItemLines, whitespaceLineBefore || whitespaceLineAfter ); foreach ( IHtmlable entry in nextListItem.GetContent() ) { listItems.AddLast( entry ); } // Jump over lines just parsed currentIndex += (endIndex - currentIndex); // Whitespace after previous entry becomes before next entry whitespaceLineBefore = whitespaceLineAfter; /* * If there's further whitespace after parsed section * (for some reason) then jump over this too */ while ( (currentIndex < listLines.Count) && ( ContainsOnlyWhitespace( lines[currentIndex] ) ) ) { currentIndex++; } } result.Success = true; result.AddContent( new MarkdownList( Utils.LinkedListToArray( listItems ), type ) ); return(result); }
// Parse a plain paragraph public static ParseResult ParseFrom( ParseInput input ) { ArraySegment <string> lines = input.Lines(); ParseResult result = new ParseResult(); LinkedList <IHtmlable> innerContent = new LinkedList <IHtmlable>(); // The paragraph doesn't get parsed past the first blank line int endIndex = 0; while ( (endIndex < lines.Count) && ( !ContainsOnlyWhitespace( lines[endIndex] ) ) ) { endIndex++; } int i = 0; while (i < endIndex) { lines = input.Lines(); if (MarkdownCodeBlock.CanParseFrom(input)) { ParseResult innerResult = MarkdownCodeBlock.ParseFrom(input); foreach (IHtmlable entry in innerResult.GetContent()) { innerContent.AddLast(entry); } } else { string line = lines[0]; if (endsWithAtLeastTwoSpaces(line)) { string shortened = StripTrailingWhitespace(line); foreach ( IHtmlable entry in MarkdownParser.ParseInnerText( new ParseInput( input, shortened ) ) ) { innerContent.AddLast(entry); } innerContent.AddLast( new MarkdownLinebreak() ); } else { foreach ( IHtmlable entry in MarkdownParser.ParseInnerText( new ParseInput( input, line ) ) ) { innerContent.AddLast(entry); } /* * If this is not the last line, * it doesn't end in a manual linebreak * and the user hasn't added a space themselves * we need to add a space at the end */ if ( (i < (endIndex - 1)) && (line.Length > 0) && (line[^ 1] != ' ')