private static IEnumerable<IConverterHook> GetPostConverterHookPlaceholders()
        {
            var fencedBlockQuote = new RegexReplaceConverterHook(
                ConverterHookType.PostConversion,
                WikiDownPlaceholderHelper.GetPostFencedBlockPattern(WikiDownPlaceholderHelper.BlockquotePlaceHolder),
                "<blockquote>$1</blockquote>");
            yield return fencedBlockQuote;

            var fencedStrikeThrough = new RegexReplaceConverterHook(
                ConverterHookType.PostConversion,
                WikiDownPlaceholderHelper.GetPostFencedBlockPattern(WikiDownPlaceholderHelper.StrikeThroughPlaceHolder),
                innerRules:
                    new[]
                        {
                            new RegexReplaceRule(
                                string.Format(
                                    @"\n*<p>\[\[\[\[\/?{0}\]\]\]\]<\/p>\n*",
                                    WikiDownPlaceholderHelper.StrikeThroughPlaceHolder),
                                string.Empty),
                            new RegexReplaceRule(@"(<p>)(?!\[.*\])([\w\W]*?)(<\/p>)", "<p><del>$2</del></p>")
                        });
            yield return fencedStrikeThrough;

            var infoBox = new RegexReplaceConverterHook(
                ConverterHookType.PostConversion,
                WikiDownPlaceholderHelper.GetPostFencedBlockPattern(WikiDownPlaceholderHelper.InfoBoxPlaceHolder),
                string.Format(
                    "<div class=\"{0}\">" + "<div class=\"{1}\">$1</div></div>",
                    InfoBoxCssClass + " panel panel-default",
                    "panel-body"));
            yield return infoBox;
        }
        public void RegisterPreConversion(
            string regexPattern,
            string regexReplace,
            bool ignoreCase = true,
            bool multiline = true)
        {
            var converterHook = new RegexReplaceConverterHook(
                ConverterHookType.PreConversion,
                regexPattern,
                regexReplace,
                null,
                ignoreCase,
                multiline);

            this.Register(converterHook);
        }
 public void Register(RegexReplaceConverterHook converterHook)
 {
     this.converterHooks.Add(converterHook);
 }
        private static IEnumerable<IConverterHook> GetPostConverterHooks()
        {
            for (int i = 5; i >= 1; i--)
            {
                string pattern = string.Format(@"^<h{0}([^>]*)>([^<]*)<\/h{0}>$", i);
                string replace = string.Format("<h{0}$1>$2</h{0}>", i + 1);
                yield return new RegexReplaceConverterHook(ConverterHookType.PostConversion, pattern, replace);
            }

            var strikeThrough = new RegexReplaceConverterHook(
                ConverterHookType.PostConversion,
                @"~~(.+?)~~",
                "<del>$1</del>",
                multiline: false);
            yield return strikeThrough;

            // TODO: Responsive images http://getbootstrap.com/css/#images-responsive

            var mediaObjects = new RegexReplaceConverterHook(
                ConverterHookType.PostConversion,
                @"^(<[^>]+>)(<img[^>]+>)\n([^<\n]+)(<\/[^>]+>)$",
                "<div class=\"media\"><div class=\"pull-left\">$2</div><div class=\"media-body\">$3</div></div>");
            yield return mediaObjects;

            var externalLinks = new RegexReplaceConverterHook(
                ConverterHookType.PostConversion,
                @"<a((?:[^>]*)href=""" + HtmlAgilityPackHelper.ExternalLinkRegexPattern
                + @"""[^>]*)>([^\[][^<]*[^\]])<\/a>",
                string.Format(
                    "<a$1 class=\"{0}\">$2<small class=\"{1}\"></small></a>",
                    ExternalLinkCssClass,
                    ExternalLinkIconCssClass));
            yield return externalLinks;

            var scrollablePreTags = new RegexReplaceConverterHook(
                ConverterHookType.PostConversion,
                @"(^|\n)<pre>",
                "$1<pre class=\"pre-scrollable\">",
                multiline: false);
            yield return scrollablePreTags;

            yield return new TableConverterHook();

            yield return new HeadingsConverterHook();

            yield return new ExternalReferencesConverterHook();

            yield return new TocConverterHook();

            var emptyTags = new RegexReplaceConverterHook(
                ConverterHookType.PostConversion,
                EmptyTagRegexPattern,
                string.Empty);
            yield return emptyTags;
        }
        private static IEnumerable<IConverterHook> GetPreConverterHooks(WikiDownConfig config)
        {
            var wikiLinksImplicit = new RegexReplaceConverterHook(
                ConverterHookType.PreConversion,
                @"\[\[[ ]*([^\n\]\|\#]+?)[ ]*\]\]",
                string.Format("[[$1|{0}]]", ArticleSlugPlaceholderConverterHook.EncodeArticleSlug("$1")),
                multiline: false);
            yield return wikiLinksImplicit;

            var wikiLinks = new RegexReplaceConverterHook(
                ConverterHookType.PreConversion,
                @"\[\[[ ]*([^\n\]\|]+?)[ ]*\|[ ]*([^\n\]\#]+?)[ ]*(#[^\n\]]+?)?[ ]*\]\]",
                string.Format("<a href=\"/{0}/$2/$3\">$1</a>", config.WikiPrefix),
                multiline: false);
            yield return wikiLinks;

            var wikiHashLinks = new RegexReplaceConverterHook(
                ConverterHookType.PreConversion,
                @"\[\[[ ]*([^\n\]\|]+?)[ ]*\|[ ]*#([^\n\]]+?)[ ]*\]\]",
                "<a href=\"#$2\">$1</a>",
                multiline: false);
            yield return wikiHashLinks;

            string mainArticleImplicitTagContent = string.Format(
                "{0}|$1|{1}$2",
                WikiDownTags.MainArticle,
                ArticleSlugPlaceholderConverterHook.EncodeArticleSlug("$1"));

            var mainArticleImplicit = new RegexReplaceConverterHook(
                ConverterHookType.PreConversion,
                WikiDownMarkdownHelper.FormatTagRegex(
                    @"[ ]*" + WikiDownTags.MainArticle + @"[ ]*\|[ ]*([^#\|\n]+?)(#[^\]\n\}]+?)?[ ]*"),
                WikiDownMarkdownHelper.FormatTag(mainArticleImplicitTagContent),
                multiline: false);
            yield return mainArticleImplicit;

            yield return new MainArticleConverterHook(config);

            var noRefTitle = new RegexReplaceConverterHook(
                ConverterHookType.PreConversion,
                WikiDownMarkdownHelper.FormatTagRegex(
                    @"[ ]*" + WikiDownTags.ReferenceNeeded + @"[ ]*\|[ ]*([^\]]+?)[ ]*"),
                string.Format("<sup title=\"$1\">{0}</sup>", ReferenceNeededContent),
                multiline: false);
            yield return noRefTitle;

            var noRef = new RegexReplaceConverterHook(
                ConverterHookType.PreConversion,
                WikiDownMarkdownHelper.FormatTagRegex(WikiDownTags.ReferenceNeeded),
                string.Format("<sup>{0}</sup>", ReferenceNeededContent),
                multiline: false);
            yield return noRef;

            yield return new ArticleSlugPlaceholderConverterHook();

            //var underscoredWords = new RegexReplaceConverterHook(
            //    ConverterHookType.PreConversion,
            //    @"(([A-Za-z0-9_!]+_)+([A-Za-z0-9_!]*))(?![^<]*>|[^<>]*</)",
            //    regexPatternReplaces: new Dictionary<string, string> { { "_", @"\_" } });
            //yield return underscoredWords;
        }
        private static IEnumerable<IConverterHook> GetPreConverterHookPlaceholders()
        {
            var fencedBlockquotePlaceHolder = new RegexReplaceConverterHook(
                ConverterHookType.PreConversion,
                WikiDownPlaceholderHelper.GetPreFencedBlockPattern(">>>"),
                WikiDownPlaceholderHelper.GetFencedBlockReplace(WikiDownPlaceholderHelper.BlockquotePlaceHolder));
            yield return fencedBlockquotePlaceHolder;

            var fencedStrikeThroughPlaceHolder = new RegexReplaceConverterHook(
                ConverterHookType.PreConversion,
                WikiDownPlaceholderHelper.GetPreFencedBlockPattern("~~~"),
                WikiDownPlaceholderHelper.GetFencedBlockReplace(WikiDownPlaceholderHelper.StrikeThroughPlaceHolder));
            yield return fencedStrikeThroughPlaceHolder;

            var infoBoxPlaceHolder = new RegexReplaceConverterHook(
                ConverterHookType.PreConversion,
                WikiDownPlaceholderHelper.GetPreFencedBlockPattern("@@@"),
                WikiDownPlaceholderHelper.GetFencedBlockReplace(WikiDownPlaceholderHelper.InfoBoxPlaceHolder));
            yield return infoBoxPlaceHolder;

            var tablesPlaceholderTag = new RegexReplaceConverterHook(
                ConverterHookType.PreConversion,
                TableConverterHook.PlaceholderRegexPattern,
                WikiDownPlaceholderHelper.GetFencedBlockReplace(WikiDownPlaceholderHelper.TablePlaceholder));
            yield return tablesPlaceholderTag;
        }