forked from xoofx/markdig
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request xoofx#139 from kenmuse/enhance/yaml-frontmatter
Implement Pandoc compatible front matter parsing
- Loading branch information
Showing
4 changed files
with
273 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,128 @@ | ||
// Copyright (c) Alexandre Mutel. All rights reserved. | ||
// This file is licensed under the BSD-Clause 2 license. | ||
// See the license.txt file in the project root for more information. | ||
using Markdig.Helpers; | ||
using Markdig.Parsers; | ||
using Markdig.Syntax; | ||
|
||
namespace Markdig.Extensions.Yaml | ||
{ | ||
/// <summary> | ||
/// Block parser for a YAML frontmatter. | ||
/// </summary> | ||
/// <seealso cref="Markdig.Parsers.FencedBlockParserBase{YamlFrontMatterBlock}" /> | ||
public class YamlFrontMatterParser : FencedBlockParserBase<YamlFrontMatterBlock> | ||
/// <seealso cref="YamlFrontMatterBlock" /> | ||
public class YamlFrontMatterParser : BlockParser | ||
{ | ||
// We reuse a FencedCodeBlock parser to grab a frontmatter, only active if it happens on the first line of the document. | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="FencedCodeBlockParser"/> class. | ||
/// Initializes a new instance of the <see cref="YamlFrontMatterParser"/> class. | ||
/// </summary> | ||
public YamlFrontMatterParser() | ||
{ | ||
OpeningCharacters = new[] { '-' }; | ||
InfoPrefix = null; | ||
// We expect only 3 --- at the beginning of the file no more, no less | ||
MinimumMatchCount = 3; | ||
MaximumMatchCount = 3; | ||
this.OpeningCharacters = new[] { '-' }; | ||
} | ||
|
||
protected override YamlFrontMatterBlock CreateFencedBlock(BlockProcessor processor) | ||
/// <summary> | ||
/// Creates the front matter block. | ||
/// </summary> | ||
/// <param name="processor">The block processor</param> | ||
/// <returns>The front matter block</returns> | ||
protected virtual YamlFrontMatterBlock CreateFrontMatterBlock(BlockProcessor processor) | ||
{ | ||
return new YamlFrontMatterBlock(this); | ||
} | ||
|
||
/// <summary> | ||
/// Tries to match a block opening. | ||
/// </summary> | ||
/// <param name="processor">The parser processor.</param> | ||
/// <returns>The result of the match</returns> | ||
public override BlockState TryOpen(BlockProcessor processor) | ||
{ | ||
// We expect no indentation for a fenced code block. | ||
if (processor.IsCodeIndent) | ||
{ | ||
return BlockState.None; | ||
} | ||
|
||
// Only accept a frontmatter at the beginning of the file | ||
if (processor.LineIndex != 0) | ||
if (processor.Start != 0) | ||
{ | ||
return BlockState.None; | ||
} | ||
|
||
int count = 0; | ||
var line = processor.Line; | ||
char c = line.CurrentChar; | ||
|
||
// Must consist of exactly three dashes | ||
while (c == '-' && count < 4) | ||
{ | ||
count++; | ||
c = line.NextChar(); | ||
} | ||
|
||
// If three dashes (optionally followed by whitespace) | ||
// this is a YAML front matter blcok | ||
if (count == 3 && (c == '\0' || c.IsWhitespace()) && line.TrimEnd()) | ||
{ | ||
// Create a front matter block | ||
var block = this.CreateFrontMatterBlock(processor); | ||
block.Column = processor.Column; | ||
block.Span.Start = 0; | ||
block.Span.End = line.Start; | ||
|
||
// Store the number of matched string into the context | ||
processor.NewBlocks.Push(block); | ||
|
||
// Discard the current line as it is already parsed | ||
return BlockState.ContinueDiscard; | ||
} | ||
|
||
return BlockState.None; | ||
} | ||
|
||
/// <summary> | ||
/// Tries to continue matching a block already opened. | ||
/// </summary> | ||
/// <param name="processor">The parser processor.</param> | ||
/// <param name="block">The block already opened.</param> | ||
/// <returns>The result of the match. By default, don't expect any newline</returns> | ||
public override BlockState TryContinue(BlockProcessor processor, Block block) | ||
{ | ||
char matchChar; | ||
int count = 0; | ||
var c = processor.CurrentChar; | ||
|
||
// Determine if we have a closing fence. | ||
// It can start or end with either <c>---</c> or <c>...</c> | ||
var line = processor.Line; | ||
if (processor.Column == 0 && (c == '-' || c == '.')) | ||
{ | ||
matchChar = c; | ||
|
||
while (c == matchChar) | ||
{ | ||
c = line.NextChar(); | ||
count++; | ||
} | ||
|
||
// If we have a closing fence, close it and discard the current line | ||
// The line must contain only fence characters and optional following whitespace. | ||
if (count == 3 && !processor.IsCodeIndent && (c == '\0' || c.IsWhitespace()) && line.TrimEnd()) | ||
{ | ||
block.UpdateSpanEnd(line.Start - 1); | ||
|
||
// Don't keep the last line | ||
return BlockState.BreakDiscard; | ||
} | ||
} | ||
|
||
// Reset the indentation to the column before the indent | ||
processor.GoToColumn(processor.ColumnBeforeIndent); | ||
|
||
return base.TryOpen(processor); | ||
return BlockState.Continue; | ||
} | ||
} | ||
} |