public virtual IMarkdownToken TryMatch(IMarkdownParser parser, IMarkdownParsingContext context) { var match = OrderList.Match(context.CurrentMarkdown); if (match.Length == 0) { match = UnorderList.Match(context.CurrentMarkdown); if (match.Length == 0) { return(null); } } var sourceInfo = context.Consume(match.Length); var bull = match.Groups[2].Value; var cap = match.Groups[0].Value.Match(Item); var next = false; var l = cap.Length; int i = 0; var tokens = new List <IMarkdownToken>(); var lineOffset = 0; var lines = 0; for (; i < l; i++) { var item = cap[i]; lines = CountLine(item); // Remove the list item's bullet // so it is seen as the next token. var space = item.Length; item = item.ReplaceRegex(Regexes.Lexers.LeadingBullet, string.Empty); // Outdent whatever the // list item contains. Hacky. if (item.IndexOf("\n ") > -1) { space -= item.Length; item = !parser.Options.Pedantic ? Regex.Replace(item, "^ {1," + space + "}", "", RegexOptions.Multiline) : Regex.Replace(item, @"^ {1,4}", "", RegexOptions.Multiline); } // Determine whether item is loose or not. // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ // for discount behavior. var loose = next || Regex.IsMatch(item, @"\n\n(?!\s*$)"); if (i != l - 1 && item.Length != 0) { next = item[item.Length - 1] == '\n'; if (!loose) { loose = next; } } tokens.Add( new TwoPhaseBlockToken( this, parser.Context, sourceInfo.Copy(item, lineOffset), (p, t) => { var c = p.SwitchContext(MarkdownBlockContext.IsTop, false); if (!loose) { var bc = (MarkdownBlockContext)p.Context; c = p.SwitchContext( bc.SetRules( ImmutableList.Create <IMarkdownRule>( this, new MarkdownNewLineBlockRule(), new MarkdownTextBlockRule()))); } var blockTokens = p.Tokenize(t.SourceInfo.Copy(item)); p.SwitchContext(c); blockTokens = TokenHelper.ParseInlineToken(p, this, blockTokens, loose, t.SourceInfo); return(new MarkdownListItemBlockToken(t.Rule, t.Context, blockTokens, loose, t.SourceInfo)); })); lineOffset += lines; } return(new MarkdownListBlockToken(this, parser.Context, tokens.ToImmutableArray(), bull.Length > 1, sourceInfo)); }
public virtual IMarkdownToken TryMatch(IMarkdownParser parser, ref string source) { var match = Regexes.Block.List.Match(source); if (match.Length == 0) { return(null); } source = source.Substring(match.Length); var bull = match.Groups[2].Value; var cap = match.Groups[0].Value.Match(Item); var next = false; var l = cap.Length; int i = 0; var tokens = new List <IMarkdownToken>(); for (; i < l; i++) { var item = cap[i]; // Remove the list item's bullet // so it is seen as the next token. var space = item.Length; item = item.ReplaceRegex(Regexes.Lexers.LeadingBullet, string.Empty); // Outdent whatever the // list item contains. Hacky. if (item.IndexOf("\n ") > -1) { space -= item.Length; item = !parser.Options.Pedantic ? Regex.Replace(item, "^ {1," + space + "}", "", RegexOptions.Multiline) : Regex.Replace(item, @"^ {1,4}", "", RegexOptions.Multiline); } // Determine whether the next list item belongs here. // Backpedal if it does not belong in this list. if (parser.Options.SmartLists && i != l - 1) { var b = Bullet.Apply(cap[i + 1])[0]; // !!!!!!!!!!! if (bull != b && !(bull.Length > 1 && b.Length > 1)) { source = string.Join("\n", cap.Skip(i + 1)) + source; i = l - 1; } } // Determine whether item is loose or not. // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ // for discount behavior. var loose = next || Regex.IsMatch(item, @"\n\n(?!\s*$)"); if (i != l - 1 && item.Length != 0) { next = item[item.Length - 1] == '\n'; if (!loose) { loose = next; } } var c = parser.SwitchContext(MarkdownBlockContext.IsTop, false); var blockTokens = parser.Tokenize(item); blockTokens = TokenHelper.ParseInlineToken(parser, this, blockTokens, loose); tokens.Add(new MarkdownListItemBlockToken(this, parser.Context, blockTokens, loose, item)); parser.SwitchContext(c); } return(new MarkdownListBlockToken(this, parser.Context, tokens.ToImmutableArray(), bull.Length > 1, match.Value)); }
public StringBuffer Mark(SourceInfo sourceInfo, IMarkdownContext context) { var result = StringBuffer.Empty; var parser = Parser; if (context != null) { parser.SwitchContext(context); } var preprocessedSourceInfo = sourceInfo.Copy(Preprocess(sourceInfo.Markdown)); var tokens = parser.Tokenize(preprocessedSourceInfo); if (parser.Context is MarkdownBlockContext) { tokens = TokenHelper.CreateParagraghs( parser, MarkdownParagraphBlockRule.Instance, tokens, true, preprocessedSourceInfo); } // resolve two phase token tokens = RewriteTokens( tokens, sourceInfo.File, new MarkdownRewriteEngine( this, MarkdownTokenRewriterFactory.Loop( MarkdownTokenRewriterFactory.FromLambda <IMarkdownRewriteEngine, TwoPhaseBlockToken>( (e, t) => t.Extract(parser)), MaxExtractCount + 1))); // Aggregate tokens. foreach (var agg in TokenAggregators) { tokens = RewriteTokens( tokens, sourceInfo.File, new MarkdownAggregateEngine( this, agg)); } // customized rewriter. tokens = RewriteTokens( tokens, sourceInfo.File, RewriteEngine); if (Options.ShouldFixId) { // fix id. var idTable = new Dictionary <string, int>(); tokens = RewriteTokens( tokens, sourceInfo.File, new MarkdownRewriteEngine( this, MarkdownTokenRewriterFactory.FromLambda <IMarkdownRewriteEngine, MarkdownHeadingBlockToken>( (e, t) => t.RewriteId(idTable)))); } if (TokenTreeValidator != null) { TokenTreeValidator.Validate(tokens); } var renderer = Renderer; foreach (var token in tokens) { result += renderer.Render(token); } return(result); }