public override BlockState TryOpen(BlockProcessor processor) { var result = TryContinue(processor, null); if (result == BlockState.Continue) { // Save the column where we need to go back var column = processor.Column; var sourceStartPosition = processor.Start; // Unwind all indents all spaces before in order to calculate correct span processor.UnwindAllIndents(); var codeBlock = new CodeBlock(this) { Column = processor.Column, Span = new SourceSpan(processor.Start, processor.Line.End), LinesBefore = processor.UseLinesBefore(), NewLine = processor.Line.NewLine, }; var codeBlockLine = new CodeBlockLine { TriviaBefore = processor.UseTrivia(sourceStartPosition - 1) }; codeBlock.CodeBlockLines.Add(codeBlockLine); processor.NewBlocks.Push(codeBlock); // Go back to the correct column processor.GoToColumn(column); } return(result); }
public override BlockState TryContinue(BlockProcessor processor, Block?block) { if (!processor.IsCodeIndent || processor.IsBlankLine) { if (block is null || !processor.IsBlankLine) { if (block != null) { var codeBlock = (CodeBlock)block; // add trailing blank lines to blank lines stack of processor for (int i = codeBlock.Lines.Count - 1; i >= 0; i--) { var line = codeBlock.Lines.Lines[i]; if (line.Slice.IsEmpty) { codeBlock.Lines.RemoveAt(i); if (processor.TrackTrivia) { processor.LinesBefore ??= new List <StringSlice>(); processor.LinesBefore.Add(line.Slice); } } else { break; } } } return(BlockState.None); } } // If we don't have a blank line, we reset to the indent if (processor.Indent > 4) { processor.GoToCodeIndent(); } if (block != null) { block.UpdateSpanEnd(processor.Line.End); // lines var cb = (CodeBlock)block; var codeBlockLine = new CodeBlockLine(); cb.CodeBlockLines.Add(codeBlockLine); if (processor.TrackTrivia) { codeBlockLine.TriviaBefore = processor.UseTrivia(processor.Start - 1); cb.NewLine = processor.Line.NewLine; // ensure block newline is last newline } } return(BlockState.Continue); }
protected override FencedCodeBlock CreateFencedBlock(BlockProcessor processor) { return(new FencedCodeBlock(this) { IndentCount = processor.Indent, LinesBefore = processor.UseLinesBefore(), TriviaBefore = processor.UseTrivia(processor.Start - 1), NewLine = processor.Line.NewLine, }); }
protected override FencedCodeBlock CreateFencedBlock(BlockProcessor processor) { var codeBlock = new FencedCodeBlock(this) { IndentCount = processor.Indent, }; if (processor.TrackTrivia) { codeBlock.LinesBefore = processor.UseLinesBefore(); codeBlock.TriviaBefore = processor.UseTrivia(processor.Start - 1); codeBlock.NewLine = processor.Line.NewLine; } return(codeBlock); }
public override BlockState TryOpen(BlockProcessor processor) { // If we are in a CodeIndent, early exit if (processor.IsCodeIndent) { return(BlockState.None); } // 4.2 ATX headings // An ATX heading consists of a string of characters, parsed as inline content, // between an opening sequence of 1–6(configurable) unescaped # characters and an optional // closing sequence of any number of unescaped # characters. The opening sequence // of # characters must be followed by a space or by the end of line. The optional // closing sequence of #s must be preceded by a space and may be followed by spaces // only. The opening # character may be indented 0-3 spaces. The raw contents of // the heading are stripped of leading and trailing spaces before being parsed as // inline content. The heading level is equal to the number of # characters in the // opening sequence. var column = processor.Column; var line = processor.Line; var sourcePosition = line.Start; var c = line.CurrentChar; var matchingChar = c; Debug.Assert(MaxLeadingCount > 0); int leadingCount = 0; while (c != '\0' && leadingCount <= MaxLeadingCount) { if (c != matchingChar) { break; } c = processor.NextChar(); leadingCount++; } // A space is required after leading # if (leadingCount > 0 && leadingCount <= MaxLeadingCount && (c.IsSpaceOrTab() || c == '\0')) { StringSlice trivia = StringSlice.Empty; if (processor.TrackTrivia && c.IsSpaceOrTab()) { trivia = new StringSlice(processor.Line.Text, processor.Start, processor.Start); processor.NextChar(); } // Move to the content var headingBlock = new HeadingBlock(this) { HeaderChar = matchingChar, TriviaAfterAtxHeaderChar = trivia, Level = leadingCount, Column = column, Span = { Start = sourcePosition }, TriviaBefore = processor.UseTrivia(sourcePosition - 1), LinesBefore = processor.UseLinesBefore(), NewLine = processor.Line.NewLine, }; processor.NewBlocks.Push(headingBlock); if (!processor.TrackTrivia) { processor.GoToColumn(column + leadingCount + 1); } // Gives a chance to parse attributes TryParseAttributes?.Invoke(processor, ref processor.Line, headingBlock); // The optional closing sequence of #s must be preceded by a space and may be followed by spaces only. int endState = 0; int countClosingTags = 0; int sourceEnd = processor.Line.End; for (int i = processor.Line.End; i >= processor.Line.Start - 1; i--) // Go up to Start - 1 in order to match the space after the first ### { c = processor.Line.Text[i]; if (endState == 0) { if (c.IsSpaceOrTab()) { continue; } endState = 1; } if (endState == 1) { if (c == matchingChar) { countClosingTags++; continue; } if (countClosingTags > 0) { if (c.IsSpaceOrTab()) { processor.Line.End = i - 1; } break; } else { break; } } } // Setup the source end position of this element headingBlock.Span.End = processor.Line.End; if (processor.TrackTrivia) { var wsa = new StringSlice(processor.Line.Text, processor.Line.End + 1, sourceEnd); headingBlock.TriviaAfter = wsa; if (wsa.Overlaps(headingBlock.TriviaAfterAtxHeaderChar)) { // prevent double whitespace allocation in case of closing # i.e. "# #" headingBlock.TriviaAfterAtxHeaderChar = StringSlice.Empty; } } // We expect a single line, so don't continue return(BlockState.Break); } // Else we don't have an header processor.Line.Start = sourcePosition; processor.Column = column; return(BlockState.None); }
public override BlockState TryContinue(BlockProcessor processor, Block block) { if (processor.IsCodeIndent) { return(BlockState.None); } var quote = (QuoteBlock)block; var sourcePosition = processor.Start; // 5.1 Block quotes // A block quote marker consists of 0-3 spaces of initial indent, plus (a) the character > together with a following space, or (b) a single character > not followed by a space. var c = processor.CurrentChar; bool hasSpaceAfterQuoteChar = false; if (c != quote.QuoteChar) { if (processor.IsBlankLine) { return(BlockState.BreakDiscard); } else { quote.QuoteLines.Add(new QuoteBlockLine { QuoteChar = false, NewLine = processor.Line.NewLine, }); return(BlockState.None); } } c = processor.NextChar(); // Skip quote marker char if (c == ' ') { processor.NextColumn(); hasSpaceAfterQuoteChar = true; processor.SkipFirstUnwindSpace = true; } else if (c == '\t') { processor.NextColumn(); } var TriviaSpaceBefore = processor.UseTrivia(sourcePosition - 1); StringSlice triviaAfter = StringSlice.Empty; bool wasEmptyLine = false; if (processor.Line.IsEmptyOrWhitespace()) { processor.TriviaStart = processor.Start; triviaAfter = processor.UseTrivia(processor.Line.End); wasEmptyLine = true; } quote.QuoteLines.Add(new QuoteBlockLine { QuoteChar = true, HasSpaceAfterQuoteChar = hasSpaceAfterQuoteChar, TriviaBefore = TriviaSpaceBefore, TriviaAfter = triviaAfter, NewLine = processor.Line.NewLine, }); if (!wasEmptyLine) { processor.TriviaStart = processor.Start; } block.UpdateSpanEnd(processor.Line.End); return(BlockState.Continue); }
public override BlockState TryOpen(BlockProcessor processor) { if (processor.IsCodeIndent) { return(BlockState.None); } var sourcePosition = processor.Start; // 5.1 Block quotes // A block quote marker consists of 0-3 spaces of initial indent, plus (a) the character > together with a following space, or (b) a single character > not followed by a space. var quoteChar = processor.CurrentChar; var column = processor.Column; var c = processor.NextChar(); var quoteBlock = new QuoteBlock(this) { QuoteChar = quoteChar, Column = column, Span = new SourceSpan(sourcePosition, processor.Line.End), LinesBefore = processor.UseLinesBefore() }; bool hasSpaceAfterQuoteChar = false; if (c == ' ') { processor.NextColumn(); hasSpaceAfterQuoteChar = true; processor.SkipFirstUnwindSpace = true; } else if (c == '\t') { processor.NextColumn(); } var triviaBefore = processor.UseTrivia(sourcePosition - 1); StringSlice triviaAfter = StringSlice.Empty; bool wasEmptyLine = false; if (processor.Line.IsEmptyOrWhitespace()) { processor.TriviaStart = processor.Start; triviaAfter = processor.UseTrivia(processor.Line.End); wasEmptyLine = true; } quoteBlock.QuoteLines.Add(new QuoteBlockLine { TriviaBefore = triviaBefore, TriviaAfter = triviaAfter, QuoteChar = true, HasSpaceAfterQuoteChar = hasSpaceAfterQuoteChar, NewLine = processor.Line.NewLine, }); processor.NewBlocks.Push(quoteBlock); if (!wasEmptyLine) { processor.TriviaStart = processor.Start; } return(BlockState.Continue); }