コード例 #1
0
ファイル: AzureMarked.cs プロジェクト: z784916/docfx-1
        public static string Markup(
            string src,
            string path = null,
            IReadOnlyDictionary <string, AzureFileInfo> azureMarkdownFileInfoMapping = null,
            IReadOnlyDictionary <string, AzureVideoInfo> azureVideoInfoMapping       = null,
            IReadOnlyDictionary <string, AzureFileInfo> azureResourceFileInfoMapping = null)
        {
            var engine  = (MarkdownEngine)_builder.CreateEngine(_renderer);
            var context = engine.Context;

            if (path != null)
            {
                context = engine.Context.CreateContext(engine.Context.Variables.SetItem("path", path));
            }

            if (azureMarkdownFileInfoMapping != null && azureMarkdownFileInfoMapping.Count != 0)
            {
                context = context.CreateContext(context.Variables.SetItem("azureMarkdownFileInfoMapping", azureMarkdownFileInfoMapping));
            }

            if (azureVideoInfoMapping != null && azureVideoInfoMapping.Count != 0)
            {
                context = context.CreateContext(context.Variables.SetItem("azureVideoInfoMapping", azureVideoInfoMapping));
            }

            if (azureResourceFileInfoMapping != null && azureResourceFileInfoMapping.Count != 0)
            {
                context = context.CreateContext(context.Variables.SetItem("azureResourceFileInfoMapping", azureResourceFileInfoMapping));
            }

            return(engine.Mark(SourceInfo.Create(MarkdownEngine.Normalize(src), path), context));
        }
コード例 #2
0
        private ISourceInfo GetProperyByPath(MapSourcePropertyAttribute srcPropMap, object sourceValue)
        {
            object propValue;
            var    path = srcPropMap.Path.Split('.');

            PropertyInfo prop;

            propValue = sourceValue;

            for (int i = 0; i < path.Length; i++)
            {
                prop = TryFindAppropriateProperty(path[i], propValue.GetType());
                if (prop == null)
                {
                    propValue = null;
                    break;
                }
                propValue = prop.GetValue(propValue);
                if (propValue == null)
                {
                    return(null);
                }
            }
            return(SourceInfo.Create(propValue));
        }
コード例 #3
0
 protected override ISourceInfo ResolveSourceValue(MappingMemberInfo memberInfo)
 {
     if (PropertyToResolve.Name == memberInfo.Name)
     {
         return(SourceInfo.Create(ProertyValue));
     }
     return(null);
 }
コード例 #4
0
ファイル: TabGroupAggregator.cs プロジェクト: roji/docfx
 public SourceInfo GetContentSourceInfo() =>
 SourceInfo.Create(
     Content.Aggregate(
         StringBuffer.Empty,
         (s, t) => s + t.SourceInfo.Markdown
         ).ToString(),
     HeadSource.File,
     Content.FirstOrDefault()?.SourceInfo.LineNumber ?? HeadSource.LineNumber);
コード例 #5
0
ファイル: DfmEngine.cs プロジェクト: wanyi01/docfx
 internal string InternalMarkup(string src, IMarkdownContext context) =>
 Mark(
     SourceInfo.Create(
         Normalize(src),
         context.GetFilePathStack().Peek()
         ),
     context
     ).ToString();
コード例 #6
0
 public ISourceInfo ResolveSourceValue(ParameterInfo paramInfo, object source)
 {
     //optional parametr - defaut value or default(T)
     if (paramInfo.IsOptional)
     {
         var value = paramInfo.HasDefaultValue ? paramInfo.DefaultValue : TypeHelpers.GetDefault(paramInfo.ParameterType);
         return(SourceInfo.Create(value));
     }
     return(null);
 }
コード例 #7
0
        public ISourceInfo ResolveSourceValue(IPropertyMappingInfo propertyInfo, object source)
        {
            var    key = BuilderUtils.GetKey(propertyInfo);
            object value;

            if (propertyInjections.TryGetValue(key, out value))
            {
                return(SourceInfo.Create(value));
            }
            return(null);
        }
コード例 #8
0
        protected override ISourceInfo ResolveSourceValue(MappingMemberInfo memberInfo)
        {
            var injectInstanceAttribute = memberInfo.Attributes.FirstOrDefault(x => x is InjectInstanceAttribute) as InjectInstanceAttribute;

            if (!IsMemberSuitable(memberInfo))
            {
                return(null);
            }

            object value;
            var    result = locator.TryResolve(memberInfo.Type, injectInstanceAttribute != null ? injectInstanceAttribute.Name : String.Empty, out value);

            return(result ? SourceInfo.Create(value) : null);
        }
コード例 #9
0
        protected override ISourceInfo ResolveSourceValue(MappingMemberInfo memberInfo)
        {
            IDictionary <string, TProp> sourceValues = memberInfo.SourceInstance as IDictionary <string, TProp>;

            if (sourceValues == null)
            {
                return(null);
            }

            TProp sourceProp;
            var   sourceFound = sourceValues.TryGetValue(memberInfo.Name, out sourceProp);

            return(!sourceFound ? null : SourceInfo.Create(sourceProp));;
        }
コード例 #10
0
        public ISourceInfo ResolveSourceValue(IPropertyMappingInfo propInfo, object source)
        {
            var propInfoKey = BuilderUtils.GetKey(propInfo);
            KeyValuePair <string, Type> valueType;

            if (PropertyInjectionResolvers.TryGetValue(propInfoKey, out valueType))
            {
                object value;
                if (locator.TryResolve(valueType.Value, valueType.Key, out value))
                {
                    return(SourceInfo.Create(value));
                }
            }
            return(null);
        }
コード例 #11
0
        protected override ISourceInfo ResolveSourceValue(MappingMemberInfo memberInfo)
        {
            var sourceValue = memberInfo.SourceInstance;

            if (sourceValue == null)
            {
                return(null);
            }
            if (memberInfo.Type == memberInfo.SourceType)
            {
                return(SourceInfo.Create(sourceValue));
            }
            ;

            return(null);
        }
コード例 #12
0
        public IMarkdownToken TryMatch(IMarkdownParser engine, IMarkdownParsingContext context)
        {
            var match = AzureIncludeRegex.Match(context.CurrentMarkdown);

            if (match.Length == 0)
            {
                return(null);
            }
            var sourceInfo = context.Consume(match.Length);

            // [!azure.include[title](path "optionalTitle")]
            // 1. Get include file path
            var path = match.Groups[2].Value;

            // 2. Get title
            var value = match.Groups[1].Value;
            var title = match.Groups[4].Value;

            if (!PathUtility.IsRelativePath(path))
            {
                Logger.LogWarning($"Azure inline include path {path} is not a relative path, can't expand it");
                return(new MarkdownTextToken(this, engine.Context, match.Value, sourceInfo));
            }

            // 3. Apply inline rules to the included content
            object currentFilePath;

            if (!engine.Context.Variables.TryGetValue("path", out currentFilePath))
            {
                Logger.LogWarning($"Can't get path for the file that ref azure inline include file, return MarkdownTextToken. Raw: {match.Value}");
                return(new MarkdownTextToken(this, engine.Context, match.Value, sourceInfo));
            }

            var includeFilePath = PathUtility.NormalizePath(Path.Combine(Path.GetDirectoryName(currentFilePath.ToString()), path));

            if (!File.Exists(includeFilePath))
            {
                Logger.LogWarning($"Can't get include file path {includeFilePath} in the file {currentFilePath}, return MarkdownTextToken. Raw: {match.Value}");
                return(new MarkdownTextToken(this, engine.Context, match.Value, sourceInfo));
            }

            return(new TwoPhaseBlockToken(this, engine.Context, sourceInfo, (p, t) =>
            {
                var inlineTokens = p.Tokenize(SourceInfo.Create(MarkdownEngine.Normalize(File.ReadAllText(includeFilePath)), includeFilePath));
                return new AzureIncludeInlineToken(t.Rule, t.Context, path, value, title, inlineTokens, match.Groups[0].Value, t.SourceInfo);
            }));
        }
コード例 #13
0
 private void IconButton_Click_3(object sender, RoutedEventArgs e)
 {
     try
     {
         var sfd = new SaveFileDialog
         {
             Filter = "Markdown Files (*.md)|*.md"
         };
         if (sfd.ShowDialog() == true)
         {
             //count up null: 25
             //Let's pretend to know a little about markdown 'lite' instead of manipulating string template which will make Team SH real clever
             var result   = StringBuffer.Empty;
             var mdra     = new MarkdownRendererAdapter(null, new InsetSDNSMarkdownRenderer(), null, null);
             var rthToken = new InlineContent(
                 ImmutableArray.Create((IMarkdownToken) new MarkdownTextToken(null, null, null, SourceInfo.Create($"{sfd.SafeFileName} generated by WPF_dnscrypt_proxy_md", null))));
             var rhToken = new MarkdownHeadingBlockToken(null, null, rthToken, null, 1, SourceInfo.Create(null, null));
             result += mdra.Render(rhToken);
             foreach (dynamic item in lv.Items)
             {
                 var thToken = new InlineContent(ImmutableArray.Create((IMarkdownToken) new MarkdownTextToken(null, null, null, SourceInfo.Create(item.Name, null))));
                 var hToken  = new MarkdownHeadingBlockToken(null, null, thToken, null, 2, SourceInfo.Create(null, null));
                 result += mdra.Render(hToken);
                 using (var stamp = GO_WriteStamp(JsonConvert.SerializeObject(item.STAMP)))
                 {
                     var sToken = new SDNSBlockToken(null, null, SourceInfo.Create(null, null), stamp);
                     result += mdra.Render(sToken);
                 }
             }
             File.WriteAllText(sfd.FileName, result);
             if (!GO_CreateSign(sfd.FileName))
             {
                 Xceed.Wpf.Toolkit.MessageBox.Show("Failed to create signature.");
             }
             else
             {
                 Xceed.Wpf.Toolkit.MessageBox.Show("Saved.");
             }
         }
     }
     catch (Exception ex)
     {
         Xceed.Wpf.Toolkit.MessageBox.Show(ex.ToString());
     }
 }
コード例 #14
0
ファイル: AzureIncludeBlockRule.cs プロジェクト: runt18/docfx
        public IMarkdownToken TryMatch(IMarkdownParser parser, IMarkdownParsingContext context)
        {
            var match = AzureIncludeRegex.Match(context.CurrentMarkdown);

            if (match.Length == 0)
            {
                return(null);
            }
            var sourceInfo = context.Consume(match.Length);

            // [!azure.include[title](path "optionalTitle")]
            // 1. Get include file path
            var path = match.Groups[2].Value;

            // 2. Get title
            var value = match.Groups[1].Value;
            var title = match.Groups[4].Value;

            if (!TypeForwardedToPathUtility.IsRelativePath(path))
            {
                Logger.LogWarning($"Azure inline include path {path} is not a relative path, can't expand it");
                return(new MarkdownTextToken(this, parser.Context, match.Value, sourceInfo));
            }

            object currentFilePath;

            if (!parser.Context.Variables.TryGetValue("path", out currentFilePath))
            {
                Logger.LogWarning($"Can't get path for the file that ref azure block include file, return MarkdownTextToken. Raw: {match.Value}");
                return(new MarkdownTextToken(this, parser.Context, match.Value, sourceInfo));
            }

            var includeFilePath = TypeForwardedToPathUtility.NormalizePath(Path.Combine(Path.GetDirectoryName(currentFilePath.ToString()), path));

            if (!File.Exists(includeFilePath))
            {
                Logger.LogWarning($"Can't get include file path {includeFilePath} in the file {currentFilePath}, return MarkdownTextToken. Raw: {match.Value}");
                return(new MarkdownTextToken(this, parser.Context, match.Value, sourceInfo));
            }

            var blockTokens = parser.Tokenize(SourceInfo.Create(MarkdownEngine.Normalize(File.ReadAllText(includeFilePath)), includeFilePath));

            blockTokens = TokenHelper.CreateParagraghs(parser, this, blockTokens, true, sourceInfo);
            return(new AzureIncludeBlockToken(this, parser.Context, path, value, title, blockTokens, match.Groups[0].Value, sourceInfo));
        }
コード例 #15
0
        protected override ISourceInfo ResolveSourceValue(MappingMemberInfo memberInfo)
        {
            var attribute = memberInfo.Attributes.FirstOrDefault(x => x is InjectValueAttribute) as InjectValueAttribute;

            if (attribute == null || attribute.Value == null)
            {
                Logger.LogError("InjectValueResolver::ResolveSourceValue", "Mappling value is not set");
                return(null);
            }

            if (attribute.Value is string && string.IsNullOrWhiteSpace(attribute.Value.ToString()))
            {
                Logger.LogError("InjectValueResolver::ResolveSourceValue", "Mappling value cannot be empty");
                return(null);
            }

            var convertedValue = Convert.ChangeType(attribute.Value, memberInfo.Type);

            return(SourceInfo.Create(convertedValue));;
        }
コード例 #16
0
ファイル: DfmEngine.cs プロジェクト: zyj0021/docfx
        internal string InternalMarkup(string src, IMarkdownContext context)
        {
            int    lineNumber = 1;
            var    normalized = Normalize(src);
            string file       = context.GetFilePathStack().Peek();

            if (context.GetIsInclude())
            {
                var match = DfmYamlHeaderBlockRule.YamlHeaderRegex.Match(normalized);
                if (match.Length > 0)
                {
                    lineNumber += normalized.Take(match.Length).Count(ch => ch == '\n');
                    Logger.LogInfo("Remove yaml header for include file.", file: file);
                    normalized = normalized.Substring(match.Length);
                }
            }
            return(Mark(
                       SourceInfo.Create(normalized, file, lineNumber),
                       context
                       ).ToString());
        }
コード例 #17
0
        private static ImmutableArray <IMarkdownToken> Tokenize(string markdown, string file)
        {
            var gfm        = new GfmEngineBuilder(new Options()).CreateEngine(new HtmlRenderer());
            var sourceInfo = SourceInfo.Create(markdown.Replace("\r\n", "\n"), file);

            var tokens = gfm.Parser.Tokenize(sourceInfo);

            tokens = TokenHelper.CreateParagraghs(
                gfm.Parser,
                MarkdownParagraphBlockRule.Instance,
                tokens,
                true,
                sourceInfo);

            var rewriter =
                new MarkdownRewriteEngine(
                    gfm,
                    MarkdownTokenRewriterFactory.FromLambda <IMarkdownRewriteEngine, TwoPhaseBlockToken>(
                        (e, t) => t.Extract(gfm.Parser)));

            tokens = rewriter.Rewrite(tokens);
            return(tokens);
        }
コード例 #18
0
        public void TestSourceInfo_Table()
        {
            const string File   = "test.md";
            var          gfm    = new GfmEngineBuilder(new Options()).CreateEngine(new HtmlRenderer());
            var          tokens = gfm.Parser.Tokenize(
                SourceInfo.Create(@"
| H1 | H2 |
|----|----|
|R1C1|R1C2|
|R2C1|R2C2|
".Replace("\r\n", "\n"), File));
            var rewriter =
                new MarkdownRewriteEngine(
                    gfm,
                    MarkdownTokenRewriterFactory.FromLambda <IMarkdownRewriteEngine, TwoPhaseBlockToken>(
                        (e, t) => t.Extract(gfm.Parser)));

            tokens = rewriter.Rewrite(tokens);

            Assert.Equal(2, tokens.Length);
            Assert.IsType <MarkdownTableBlockToken>(tokens[1]);
            var table = (MarkdownTableBlockToken)tokens[1];

            Assert.Equal(2, table.Header.Length);
            Assert.Equal(2, table.Cells.Length);

            Assert.Equal(2, table.SourceInfo.LineNumber);
            Assert.Equal(File, table.SourceInfo.File);

            Assert.Equal(2, table.Header[0].SourceInfo.LineNumber);
            Assert.Equal(2, table.Header[1].SourceInfo.LineNumber);

            Assert.Equal(4, table.Cells[0][0].SourceInfo.LineNumber);
            Assert.Equal(4, table.Cells[0][1].SourceInfo.LineNumber);
            Assert.Equal(5, table.Cells[1][0].SourceInfo.LineNumber);
            Assert.Equal(5, table.Cells[1][1].SourceInfo.LineNumber);
        }
コード例 #19
0
        private void IconButton_Click_1(object sender, RoutedEventArgs e)
        {
            var ofd = new OpenFileDialog
            {
                Filter = "Markdown Files (*.md)|*.md"
            };

            if (ofd.ShowDialog() == true)
            {
                this.FileName.Text = ofd.FileName;
                var meb = new MarkdownEngineBuilder(new Options
                {
                });
                // BELOW essential codes copy from Microsoft Team SH(MingHang) ZI-ZHU, not so good, but works
                var builder = ImmutableList.CreateBuilder <IMarkdownRule>();
                builder.Add(new MarkdownNewLineBlockRule());
                builder.Add(new MarkdownHeadingBlockRule());
                builder.Add(new MarkdownLHeadingBlockRule());
                builder.Add(new MarkdownDefBlockRule());
                builder.Add(new SDNSBlockRule());
                builder.Add(new MarkdownTextBlockRule());
                meb.BlockRules = builder.ToImmutable();
                builder        = ImmutableList.CreateBuilder <IMarkdownRule>();
                builder.Add(new MarkdownEscapeInlineRule());
                builder.Add(new MarkdownTagInlineRule());
                builder.Add(new MarkdownLinkInlineRule());
                builder.Add(new MarkdownStrongInlineRule());
                builder.Add(new MarkdownEmInlineRule());
                builder.Add(new MarkdownBrInlineRule());
                builder.Add(new MarkdownEscapedTextInlineRule());
                builder.Add(new MarkdownTextInlineRule());
                meb.InlineRules = builder.ToImmutable();
                // End
                var me = meb.CreateEngine(null);
                try
                {
                    var tokens = me.Parser.Tokenize(SourceInfo.Create(File.ReadAllText(ofd.FileName), null));
                    MarkdownHeadingBlockToken hToken = null;
                    IMarkdownToken convert(IMarkdownToken t) =>
                    t is TwoPhaseBlockToken tpbt?tpbt.Extract(me.Parser) as MarkdownHeadingBlockToken : t;
                    MarkdownHeadingBlockToken pop(IMarkdownToken t) => t is MarkdownHeadingBlockToken mdh ? hToken = mdh : hToken;

                    var q = from item in tokens
                            let header = pop(convert(item))
                                         group item by header into g
                                         select new { g.Key, Subs = g };
                    string strSdns = null;
                    string popSub(IMarkdownToken t) => t is SDNSBlockToken sdn ? strSdns = sdn.Text : null;
                    string reset() => strSdns = null;

                    //fidelity test
                    //bool? test(string j) { using (var json = GO_ReadStamp(j)) { using (var rt = GO_WriteStamp((string)json)) { using (var h = GO_ReadStamp((string)rt)) { return h.IsInvalid; } } } }
                    dynamic stamp(string j)
                    {
                        using (var json = GO_ReadStamp(j)) { return(json.IsInvalid ? null : JsonConvert.DeserializeObject((string)json)); }
                    }
                    var refined = from item in q
                                  let text                 = ((MarkdownTextToken)item.Key.Content.Tokens[0]).Content
                                                     let n = reset()
                                                             let description = string.Concat(from sub in item.Subs
                                                                                             let t = popSub(sub)
                                                                                                     let content = sub is MarkdownTextToken mtt ? mtt.Content : "\r\n"
                                                                                                                   select content)
                                                                               let ostamp = strSdns == null ? null : stamp(strSdns)
                                                                                            //let T = strSdns == null ? null : test(strSdns)
                                                                                            select new { Name = text, Description = description, STAMP = ostamp };
                    App.GridShow       = refined.ToList();
                    MyGrid.ItemsSource = App.GridShow;
                }
                catch (Exception ex)
                {
                    Xceed.Wpf.Toolkit.MessageBox.Show(ex.ToString());
                }
            }
        }
コード例 #20
0
        public void TestSourceInfo_BlockquoteAndList()
        {
            const string File   = "test.md";
            var          gfm    = new GfmEngineBuilder(new Options()).CreateEngine(new HtmlRenderer());
            var          tokens = gfm.Parser.Tokenize(
                SourceInfo.Create(@"> blockquote
> [link text](sometarget)
> 
> - list item 1
>   - list item 1-1
>   - list item 1-2
> - list item 2
>
> more para.
".Replace("\r\n", "\n"), File));
            var rewriter =
                new MarkdownRewriteEngine(
                    gfm,
                    MarkdownTokenRewriterFactory.FromLambda <IMarkdownRewriteEngine, TwoPhaseBlockToken>(
                        (e, t) => t.Extract(gfm.Parser)));

            tokens = rewriter.Rewrite(tokens);

            Assert.Equal(1, tokens.Length);
            Assert.IsType <MarkdownBlockquoteBlockToken>(tokens[0]);
            var blockquote = (MarkdownBlockquoteBlockToken)tokens[0];

            Assert.Equal(3, blockquote.Tokens.Length);

            Assert.Equal(1, blockquote.SourceInfo.LineNumber);
            Assert.Equal(File, blockquote.SourceInfo.File);

            Assert.IsType <MarkdownParagraphBlockToken>(blockquote.Tokens[0]);
            {
                var para = (MarkdownParagraphBlockToken)blockquote.Tokens[0];

                Assert.Equal(1, para.SourceInfo.LineNumber);
                Assert.Equal(File, para.SourceInfo.File);

                Assert.Equal(2, para.InlineTokens.Tokens.Length);

                Assert.IsType <MarkdownTextToken>(para.InlineTokens.Tokens[0]);
                var text = (MarkdownTextToken)para.InlineTokens.Tokens[0];
                Assert.Equal(1, text.SourceInfo.LineNumber);
                Assert.Equal(File, text.SourceInfo.File);

                Assert.IsType <MarkdownLinkInlineToken>(para.InlineTokens.Tokens[1]);
                var link = (MarkdownLinkInlineToken)para.InlineTokens.Tokens[1];
                Assert.Equal(2, link.SourceInfo.LineNumber);
                Assert.Equal(File, link.SourceInfo.File);
            }
            Assert.IsType <MarkdownListBlockToken>(blockquote.Tokens[1]);
            {
                var list = (MarkdownListBlockToken)blockquote.Tokens[1];

                Assert.Equal(4, list.SourceInfo.LineNumber);
                Assert.Equal(File, list.SourceInfo.File);
                Assert.Equal(2, list.Tokens.Length);
                Assert.IsType <MarkdownListItemBlockToken>(list.Tokens[0]);
                {
                    var listItem = (MarkdownListItemBlockToken)list.Tokens[0];
                    Assert.Equal(4, listItem.SourceInfo.LineNumber);
                    Assert.Equal(File, listItem.SourceInfo.File);

                    Assert.IsType <MarkdownNonParagraphBlockToken>(listItem.Tokens[0]);
                    var np = (MarkdownNonParagraphBlockToken)listItem.Tokens[0];
                    Assert.Equal(1, np.Content.Tokens.Length);
                    Assert.Equal(4, np.SourceInfo.LineNumber);
                    Assert.Equal(File, np.SourceInfo.File);

                    Assert.IsType <MarkdownListBlockToken>(listItem.Tokens[1]);
                    var subList = (MarkdownListBlockToken)listItem.Tokens[1];
                    Assert.Equal(2, subList.Tokens.Length);
                    Assert.IsType <MarkdownListItemBlockToken>(subList.Tokens[0]);
                    {
                        var subListItem = (MarkdownListItemBlockToken)subList.Tokens[0];
                        Assert.Equal(5, subListItem.SourceInfo.LineNumber);
                        Assert.Equal(File, subListItem.SourceInfo.File);
                    }
                    Assert.IsType <MarkdownListItemBlockToken>(subList.Tokens[1]);
                    {
                        var subListItem = (MarkdownListItemBlockToken)subList.Tokens[1];
                        Assert.Equal(6, subListItem.SourceInfo.LineNumber);
                        Assert.Equal(File, subListItem.SourceInfo.File);
                    }
                }

                Assert.IsType <MarkdownListItemBlockToken>(list.Tokens[1]);
                {
                    var listItem = (MarkdownListItemBlockToken)list.Tokens[1];
                    Assert.Equal(7, listItem.SourceInfo.LineNumber);
                    Assert.Equal(File, listItem.SourceInfo.File);
                }
            }

            Assert.IsType <MarkdownParagraphBlockToken>(blockquote.Tokens[2]);
            {
                var para = (MarkdownParagraphBlockToken)blockquote.Tokens[2];
                Assert.Equal(9, para.SourceInfo.LineNumber);
                Assert.Equal(File, para.SourceInfo.File);
            }
        }
コード例 #21
0
        public void TestSourceInfo_Basic()
        {
            const string File   = "test.md";
            var          gfm    = new GfmEngineBuilder(new Options()).CreateEngine(new HtmlRenderer());
            var          tokens = gfm.Parser.Tokenize(
                SourceInfo.Create(@"

# HEAD1
First line.  
More line.
## HEAD2
Yeah!".Replace("\r\n", "\n"), File));
            var rewriter =
                new MarkdownRewriteEngine(
                    gfm,
                    MarkdownTokenRewriterFactory.FromLambda <IMarkdownRewriteEngine, TwoPhaseBlockToken>(
                        (e, t) => t.Extract(gfm.Parser)));

            tokens = rewriter.Rewrite(tokens);

            Assert.Equal(5, tokens.Length);
            Assert.IsType <MarkdownNewLineBlockToken>(tokens[0]);
            Assert.IsType <MarkdownHeadingBlockToken>(tokens[1]);
            Assert.IsType <MarkdownParagraphBlockToken>(tokens[2]);
            Assert.IsType <MarkdownHeadingBlockToken>(tokens[3]);
            Assert.IsType <MarkdownParagraphBlockToken>(tokens[4]);
            var para = (MarkdownParagraphBlockToken)tokens[2];

            Assert.Equal(3, para.InlineTokens.Tokens.Length);
            Assert.IsType <MarkdownTextToken>(para.InlineTokens.Tokens[0]);
            Assert.IsType <MarkdownBrInlineToken>(para.InlineTokens.Tokens[1]);
            Assert.IsType <MarkdownTextToken>(para.InlineTokens.Tokens[2]);

            Assert.Equal(1, tokens[0].SourceInfo.LineNumber);
            Assert.Equal(File, tokens[0].SourceInfo.File);
            Assert.Equal("\n\n", tokens[0].SourceInfo.Markdown);

            Assert.Equal(3, tokens[1].SourceInfo.LineNumber);
            Assert.Equal(File, tokens[1].SourceInfo.File);
            Assert.Equal("# HEAD1\n", tokens[1].SourceInfo.Markdown);

            Assert.Equal(4, tokens[2].SourceInfo.LineNumber);
            Assert.Equal(File, tokens[2].SourceInfo.File);
            Assert.Equal("First line.  \nMore line.\n", tokens[2].SourceInfo.Markdown);

            Assert.Equal(4, para.InlineTokens.Tokens[0].SourceInfo.LineNumber);
            Assert.Equal(File, para.InlineTokens.Tokens[0].SourceInfo.File);
            Assert.Equal("First line.", para.InlineTokens.Tokens[0].SourceInfo.Markdown);

            Assert.Equal(4, para.InlineTokens.Tokens[1].SourceInfo.LineNumber);
            Assert.Equal(File, para.InlineTokens.Tokens[1].SourceInfo.File);
            Assert.Equal("  \n", para.InlineTokens.Tokens[1].SourceInfo.Markdown);

            Assert.Equal(5, para.InlineTokens.Tokens[2].SourceInfo.LineNumber);
            Assert.Equal(File, para.InlineTokens.Tokens[2].SourceInfo.File);
            Assert.Equal("More line.", para.InlineTokens.Tokens[2].SourceInfo.Markdown);

            Assert.Equal(6, tokens[3].SourceInfo.LineNumber);
            Assert.Equal(File, tokens[3].SourceInfo.File);
            Assert.Equal("## HEAD2\n", tokens[3].SourceInfo.Markdown);

            Assert.Equal(7, tokens[4].SourceInfo.LineNumber);
            Assert.Equal(File, tokens[4].SourceInfo.File);
            Assert.Equal("Yeah!", tokens[4].SourceInfo.Markdown);
        }