mirror of
https://github.com/xoofx/markdig.git
synced 2026-02-06 21:36:15 +00:00
Fix issue with MarkdownPipeline that was not threadsafe and initialization was deferred at parsing time instead of pipeline build time (issue #40)
This commit is contained in:
@@ -41,7 +41,7 @@ namespace Markdig.Extensions.Emoji
|
||||
/// </summary>
|
||||
public Dictionary<string, string> SmileyToEmoji { get; }
|
||||
|
||||
public override void Initialize(InlineProcessor processor)
|
||||
public override void Initialize()
|
||||
{
|
||||
var firstChars = new HashSet<char>();
|
||||
var textToMatch = new HashSet<string>();
|
||||
|
||||
@@ -34,9 +34,10 @@ namespace Markdig.Extensions.Tables
|
||||
{
|
||||
pipeline.BlockParsers.Insert(0, new PipeTableBlockParser());
|
||||
}
|
||||
var lineBreakParser = pipeline.InlineParsers.FindExact<LineBreakInlineParser>();
|
||||
if (!pipeline.InlineParsers.Contains<PipeTableParser>())
|
||||
{
|
||||
pipeline.InlineParsers.InsertBefore<EmphasisInlineParser>(new PipeTableParser(Options));
|
||||
pipeline.InlineParsers.InsertBefore<EmphasisInlineParser>(new PipeTableParser(lineBreakParser, Options));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Parsers;
|
||||
@@ -18,14 +20,17 @@ namespace Markdig.Extensions.Tables
|
||||
/// <seealso cref="IPostInlineProcessor" />
|
||||
public class PipeTableParser : InlineParser, IPostInlineProcessor
|
||||
{
|
||||
private LineBreakInlineParser lineBreakParser;
|
||||
private readonly LineBreakInlineParser lineBreakParser;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PipeTableParser" /> class.
|
||||
/// </summary>
|
||||
/// <param name="lineBreakParser">The linebreak parser to use</param>
|
||||
/// <param name="options">The options.</param>
|
||||
public PipeTableParser(PipeTableOptions options = null)
|
||||
public PipeTableParser(LineBreakInlineParser lineBreakParser, PipeTableOptions options = null)
|
||||
{
|
||||
if (lineBreakParser == null) throw new ArgumentNullException(nameof(lineBreakParser));
|
||||
this.lineBreakParser = lineBreakParser;
|
||||
OpeningCharacters = new[] { '|', '\n' };
|
||||
Options = options ?? new PipeTableOptions();
|
||||
}
|
||||
@@ -35,12 +40,6 @@ namespace Markdig.Extensions.Tables
|
||||
/// </summary>
|
||||
public PipeTableOptions Options { get; }
|
||||
|
||||
public override void Initialize(InlineProcessor processor)
|
||||
{
|
||||
// We are using the linebreak parser
|
||||
lineBreakParser = processor.Parsers.Find<LineBreakInlineParser>() ?? new LineBreakInlineParser();
|
||||
}
|
||||
|
||||
public override bool Match(InlineProcessor processor, ref StringSlice slice)
|
||||
{
|
||||
// Only working on Paragraph block
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Markdig
|
||||
public MarkdownPipelineBuilder()
|
||||
{
|
||||
// Add all default parsers
|
||||
BlockParsers = new BlockParserList()
|
||||
BlockParsers = new OrderedList<BlockParser>()
|
||||
{
|
||||
new ThematicBreakParser(),
|
||||
new HeadingBlockParser(),
|
||||
@@ -37,7 +37,7 @@ namespace Markdig
|
||||
new ParagraphBlockParser(),
|
||||
};
|
||||
|
||||
InlineParsers = new InlineParserList()
|
||||
InlineParsers = new OrderedList<InlineParser>()
|
||||
{
|
||||
new HtmlEntityParser(),
|
||||
new LinkInlineParser(),
|
||||
@@ -56,12 +56,12 @@ namespace Markdig
|
||||
/// <summary>
|
||||
/// Gets the block parsers.
|
||||
/// </summary>
|
||||
public BlockParserList BlockParsers { get; private set; }
|
||||
public OrderedList<BlockParser> BlockParsers { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the inline parsers.
|
||||
/// </summary>
|
||||
public InlineParserList InlineParsers { get; private set; }
|
||||
public OrderedList<InlineParser> InlineParsers { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the register extensions.
|
||||
|
||||
@@ -12,13 +12,6 @@ namespace Markdig.Parsers
|
||||
/// <seealso cref="Markdig.Parsers.ParserList{Markdig.Parsers.BlockParser, Markdig.Parsers.BlockParserState}" />
|
||||
public class BlockParserList : ParserList<BlockParser, BlockProcessor>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BlockParserList"/> class.
|
||||
/// </summary>
|
||||
public BlockParserList()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BlockParserList"/> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -51,7 +51,6 @@ namespace Markdig.Parsers
|
||||
Document = document;
|
||||
document.IsOpen = true;
|
||||
Parsers = parsers;
|
||||
parsers.Initialize(this);
|
||||
OpenedBlocks = new List<Block>();
|
||||
NewBlocks = new Stack<Block>();
|
||||
root = this;
|
||||
|
||||
@@ -17,8 +17,7 @@ namespace Markdig.Parsers
|
||||
/// <summary>
|
||||
/// Initializes this parser with the specified parser processor.
|
||||
/// </summary>
|
||||
/// <param name="processor">The parser processor.</param>
|
||||
void Initialize(TProcessor processor);
|
||||
void Initialize();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of this parser in <see cref="BlockParserList"/> or <see cref="InlineParserList"/>.
|
||||
|
||||
@@ -11,20 +11,7 @@ namespace Markdig.Parsers
|
||||
/// <seealso cref="Markdig.Parsers.ParserList{Markdig.Parsers.InlineParser, Markdig.Parsers.InlineParserState}" />
|
||||
public class InlineParserList : ParserList<InlineParser, InlineProcessor>
|
||||
{
|
||||
public InlineParserList()
|
||||
{
|
||||
}
|
||||
|
||||
public InlineParserList(IEnumerable<InlineParser> parsers) : base(parsers)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registered post inline processors.
|
||||
/// </summary>
|
||||
public IPostInlineProcessor[] PostInlineProcessors { get; private set; }
|
||||
|
||||
public override void Initialize(InlineProcessor initState)
|
||||
{
|
||||
// Prepare the list of post inline processors
|
||||
var postInlineProcessors = new List<IPostInlineProcessor>();
|
||||
@@ -37,8 +24,11 @@ namespace Markdig.Parsers
|
||||
}
|
||||
}
|
||||
PostInlineProcessors = postInlineProcessors.ToArray();
|
||||
|
||||
base.Initialize(initState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registered post inline processors.
|
||||
/// </summary>
|
||||
public IPostInlineProcessor[] PostInlineProcessors { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,6 @@ namespace Markdig.Parsers
|
||||
Parsers = parsers;
|
||||
PreciseSourceLocation = preciseSourcelocation;
|
||||
lineOffsets = new List<StringLineGroup.LineOffset>();
|
||||
Parsers.Initialize(this);
|
||||
ParserStates = new object[Parsers.Count];
|
||||
LiteralInlineParser = new LiteralInlineParser();
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Markdig.Parsers.Inlines
|
||||
/// </summary>
|
||||
public CreateEmphasisInlineDelegate CreateEmphasisInline { get; set; }
|
||||
|
||||
public override void Initialize(InlineProcessor processor)
|
||||
public override void Initialize()
|
||||
{
|
||||
OpeningCharacters = new char[EmphasisDescriptors.Count];
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Markdig.Parsers
|
||||
/// </summary>
|
||||
public OrderedList<ListItemParser> ItemParsers { get; }
|
||||
|
||||
public override void Initialize(BlockProcessor processor)
|
||||
public override void Initialize()
|
||||
{
|
||||
var tempMap = new Dictionary<char, ListItemParser>();
|
||||
|
||||
|
||||
@@ -51,14 +51,10 @@ namespace Markdig.Parsers
|
||||
document = new MarkdownDocument();
|
||||
|
||||
// Initialize the block parsers
|
||||
var blockParserList = new BlockParserList();
|
||||
blockParserList.AddRange(pipeline.BlockParsers);
|
||||
blockProcessor = new BlockProcessor(stringBuilderCache, document, blockParserList);
|
||||
blockProcessor = new BlockProcessor(stringBuilderCache, document, pipeline.BlockParsers);
|
||||
|
||||
// Initialize the inline parsers
|
||||
var inlineParserList = new InlineParserList();
|
||||
inlineParserList.AddRange(pipeline.InlineParsers);
|
||||
inlineProcessor = new InlineProcessor(stringBuilderCache, document, inlineParserList, pipeline.PreciseSourceLocation)
|
||||
inlineProcessor = new InlineProcessor(stringBuilderCache, document, pipeline.InlineParsers, pipeline.PreciseSourceLocation)
|
||||
{
|
||||
DebugLog = pipeline.DebugLog
|
||||
};
|
||||
|
||||
@@ -19,8 +19,7 @@ namespace Markdig.Parsers
|
||||
/// <summary>
|
||||
/// Initializes this parser with the specified parser processor.
|
||||
/// </summary>
|
||||
/// <param name="processor">The parser processor.</param>
|
||||
public virtual void Initialize(TProcessor processor)
|
||||
public virtual void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -16,60 +16,10 @@ namespace Markdig.Parsers
|
||||
/// <seealso cref="Markdig.Helpers.OrderedList{T}" />
|
||||
public abstract class ParserList<T, TState> : OrderedList<T> where T : ParserBase<TState>
|
||||
{
|
||||
private CharacterMap<T[]> charMap;
|
||||
private T[] globalParsers;
|
||||
private readonly CharacterMap<T[]> charMap;
|
||||
private readonly T[] globalParsers;
|
||||
|
||||
protected ParserList()
|
||||
{
|
||||
}
|
||||
|
||||
protected ParserList(IEnumerable<T> parsers) : base(parsers)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of global parsers (that don't have any opening characters defined)
|
||||
/// </summary>
|
||||
public T[] GlobalParsers => globalParsers;
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the opening characters defined.
|
||||
/// </summary>
|
||||
public char[] OpeningCharacters => charMap.OpeningCharacters;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of parsers valid for the specified opening character.
|
||||
/// </summary>
|
||||
/// <param name="openingChar">The opening character.</param>
|
||||
/// <returns>A list of parsers valid for the specified opening character or null if no parsers registered.</returns>
|
||||
[MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
|
||||
public T[] GetParsersForOpeningCharacter(char openingChar)
|
||||
{
|
||||
return charMap[openingChar];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for an opening character from a registered parser in the specified string.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="start">The start.</param>
|
||||
/// <param name="end">The end.</param>
|
||||
/// <returns>Index position within the string of the first opening character found in the specified text; if not found, returns -1</returns>
|
||||
[MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
|
||||
public int IndexOfOpeningCharacter(string text, int start, int end)
|
||||
{
|
||||
return charMap.IndexOfOpeningCharacter(text, start, end);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this instance with specified parser state.
|
||||
/// </summary>
|
||||
/// <param name="initState">State of the initialize.</param>
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// Unexpected null parser found
|
||||
/// or
|
||||
/// </exception>
|
||||
public virtual void Initialize(TState initState)
|
||||
protected ParserList(IEnumerable<T> parsersArg) : base(parsersArg)
|
||||
{
|
||||
var charCounter = new Dictionary<char, int>();
|
||||
int globalCounter = 0;
|
||||
@@ -82,7 +32,7 @@ namespace Markdig.Parsers
|
||||
throw new InvalidOperationException("Unexpected null parser found");
|
||||
}
|
||||
|
||||
parser.Initialize(initState);
|
||||
parser.Initialize();
|
||||
parser.Index = i;
|
||||
if (parser.OpeningCharacters != null && parser.OpeningCharacters.Length != 0)
|
||||
{
|
||||
@@ -134,5 +84,50 @@ namespace Markdig.Parsers
|
||||
|
||||
charMap = new CharacterMap<T[]>(tempCharMap);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of global parsers (that don't have any opening characters defined)
|
||||
/// </summary>
|
||||
public T[] GlobalParsers => globalParsers;
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the opening characters defined.
|
||||
/// </summary>
|
||||
public char[] OpeningCharacters => charMap.OpeningCharacters;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of parsers valid for the specified opening character.
|
||||
/// </summary>
|
||||
/// <param name="openingChar">The opening character.</param>
|
||||
/// <returns>A list of parsers valid for the specified opening character or null if no parsers registered.</returns>
|
||||
[MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
|
||||
public T[] GetParsersForOpeningCharacter(char openingChar)
|
||||
{
|
||||
return charMap[openingChar];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for an opening character from a registered parser in the specified string.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="start">The start.</param>
|
||||
/// <param name="end">The end.</param>
|
||||
/// <returns>Index position within the string of the first opening character found in the specified text; if not found, returns -1</returns>
|
||||
[MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
|
||||
public int IndexOfOpeningCharacter(string text, int start, int end)
|
||||
{
|
||||
return charMap.IndexOfOpeningCharacter(text, start, end);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this instance with specified parser state.
|
||||
/// </summary>
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// Unexpected null parser found
|
||||
/// or
|
||||
/// </exception>
|
||||
private void Initialize()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user