public void Setup() { parser = new ReferenceInlineParser(); Mock <InlineProcessor> mockProcessor = new Mock <InlineProcessor>(new MarkdownDocument(), new InlineParserList(new InlineParser[0]), false, new MarkdownParserContext()); processor = mockProcessor.Object; }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { var previousChar = slice.PeekCharExtra(-1); if (!IsValidPreviousCharacter(previousChar)) { return(false); } List <char> pendingEmphasis; if (!IsAutoLinkValidInCurrentContext(processor, out pendingEmphasis)) { return(false); } int charactersConsumedInReference; var ticketUri = GetTicketUri(slice, out charactersConsumedInReference); if (ticketUri == null) { return(false); } AddTicketLink(processor, slice, charactersConsumedInReference, ticketUri); slice.Start += charactersConsumedInReference; return(true); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { // Allow preceding whitespace var pc = slice.PeekCharExtra(-1); if (!pc.IsWhiteSpaceOrZero()) { return(false); } var current = slice.CurrentChar; var start = slice.Start; var end = slice.Start; // Read allowed characters while (current.IsAlphaNumeric() || current == '-' || current == '_' || current == '#') { end = slice.Start; current = slice.NextChar(); } var tag = new Hashtag { Span = { Start = processor.GetSourcePosition(slice.Start, out var line, out var column) },
private void HeadingBlock_ProcessInlinesEnd(InlineProcessor processor, Inline?inline) { var identifiers = processor.Document.GetData(DeepLinkKey) as HashSet <string>; if (identifiers is null) { identifiers = new HashSet <string>(); processor.Document.SetData(DeepLinkKey, identifiers); } var headingBlock = (HeadingBlock)processor.Block !; if (headingBlock.Inline is null) { return; } // If id is already set, don't try to modify it var attributes = processor.Block !.GetAttributes(); if (attributes.Id != null) { return; } // Use internally a HtmlRenderer to strip links from a heading var stripRenderer = rendererCache.Get(); stripRenderer.Render(headingBlock.Inline); var headingText = stripRenderer.Writer.ToString() !; rendererCache.Release(stripRenderer); headingText = $"{Filename}-{headingText}"; // Urilize the link headingText = (options & DeepLinkOptions.GitHub) != 0 ? LinkHelper.UrilizeAsGfm(headingText) : LinkHelper.Urilize(headingText, (options & DeepLinkOptions.AllowOnlyAscii) != 0); // If the heading is empty, use the word "section" instead var baseHeadingId = string.IsNullOrEmpty(headingText) ? "section" : headingText; // Add a trailing -1, -2, -3...etc. in case of collision int index = 0; var headingId = baseHeadingId; var headingBuffer = StringBuilderCache.Local(); while (!identifiers.Add(headingId)) { index++; headingBuffer.Append(baseHeadingId); headingBuffer.Append('-'); headingBuffer.Append(index); headingId = headingBuffer.ToString(); headingBuffer.Length = 0; } attributes.Id = $"{headingId}"; }
public void ExtractCiteUrl_ExtractsCiteUrlIfSuccessful() { // Arrange const string dummyUrl = "dummyLink"; var dummyAuthorLinkInline = new LinkInline(); var dummyCiteLinkInline = new LinkInline(dummyUrl, null); var dummyContainerInline = new ContainerInline(); dummyContainerInline. AppendChild(dummyAuthorLinkInline). AppendChild(dummyCiteLinkInline); LeafBlock dummyCitationBlock = _mockRepository.Create <LeafBlock>(null).Object; InlineProcessor dummyInlineProcessor = MarkdigTypesFactory.CreateInlineProcessor(); dummyInlineProcessor.ProcessInlineLeaf(dummyCitationBlock); // Sets InlineProcessor.Block to dummyCitationBlock dummyCitationBlock.Inline = dummyContainerInline; // Replace container created in ProcessInlineLeaf FlexiQuoteBlock dummyFlexiQuoteBlock = CreateFlexiQuoteBlock(); dummyFlexiQuoteBlock.Add(dummyCitationBlock); Mock <FlexiQuoteBlockFactory> mockTestSubject = CreateMockFlexiQuoteBlockFactory(); mockTestSubject.Setup(m => m.NormalizeCiteLinkIndex(2, dummyFlexiQuoteBlock)).Returns(1); // Act mockTestSubject.Object.ExtractCiteUrl(dummyInlineProcessor, null); // Assert _mockRepository.VerifyAll(); Assert.Equal(dummyUrl, dummyFlexiQuoteBlock.CiteUrl); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { if (!ExtensionsHelper.MatchStart(ref slice, StartString, true)) { return(false); } var text = ExtensionsHelper.TryGetStringBeforeChars(new char[] { '\"', '\n' }, ref slice); if (text == null || text.IndexOf('\n') != -1) { return(false); } if (!ExtensionsHelper.MatchStart(ref slice, EndString, true)) { return(false); } processor.Inline = new NolocInline() { Text = text }; return(true); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { if (!ExtensionsHelper.MatchStart(ref slice, StartString, false)) { return(false); } else { if (slice.CurrentChar == '-') { slice.NextChar(); } } var includeFile = new InclusionInline(); var context = new InclusionContext(); if (!ExtensionsHelper.MatchLink(ref slice, ref context)) { return(false); } includeFile.Context = context; processor.Inline = includeFile; return(true); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { int match; string literal; if (!TryParse(ref slice, out literal, out match)) { return(false); } var startPosition = slice.Start; if (literal != null) { var matched = slice; matched.End = slice.Start + match - 1; int line; int column; processor.Inline = new HtmlEntityInline() { Original = matched, Transcoded = new StringSlice(literal), Span = new SourceSpan(processor.GetSourcePosition(startPosition, out line, out column), processor.GetSourcePosition(matched.End)), Line = line, Column = column }; slice.Start = slice.Start + match; return(true); } return(false); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { if (!slice.Match(m_StartTag)) { return(false); } var rawContent = new StringBuilder(); var current = slice.CurrentChar; while (!rawContent.ToString().EndsWith(m_EndTag)) { if (slice.IsEmpty) { return(false); } rawContent.Append(current); current = slice.NextChar(); } processor.Inline = new ProtectedTagsData(rawContent.ToString()); return(true); }
public void DocumentOnProcessInlinesBegin_DoesNotReplaceExistingLinkReferenceDefinitions() { // Arrange const string dummyLinkLabelContent = "dummyLinkLabelContent"; InlineProcessor dummyInlineProcessor = MarkdigTypesFactory.CreateInlineProcessor(); FlexiFigureBlock dummyFlexiFigureBlock = CreateFlexiFigureBlock(linkLabelContent: dummyLinkLabelContent); dummyInlineProcessor.Document.SetData(FlexiFigureBlockFactory.REFERENCE_LINKABLE_FLEXI_FIGURE_BLOCKS_KEY, new List <FlexiFigureBlock> { dummyFlexiFigureBlock }); var dummyLinkReferenceDefinition = new LinkReferenceDefinition(); dummyInlineProcessor.Document.SetLinkReferenceDefinition(dummyLinkLabelContent, dummyLinkReferenceDefinition); FlexiFigureBlockFactory testSubject = CreateFlexiFigureBlockFactory(); // Act testSubject.DocumentOnProcessInlinesBegin(dummyInlineProcessor, null); // Assert Dictionary <string, LinkReferenceDefinition> linkReferenceDefinitions = (dummyInlineProcessor.Document.GetData(typeof(LinkReferenceDefinitionGroup)) as LinkReferenceDefinitionGroup)?.Links; Assert.Single(linkReferenceDefinitions); Assert.Same(dummyLinkReferenceDefinition, linkReferenceDefinitions.Values.First()); // Doesn't get replaced }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { foreach (var p in _typographMapping.Mappings) { foreach (var f in p.Value) { var m = f(slice); if (m == null) { continue; } m.Span.Start = processor.GetSourcePosition(slice.Start, out int line, out int column); m.Line = line; m.Column = column; m.Span.End = m.Span.Start + m.Match.Length - 1; slice.Start += m.Match.Length; return(true); } } return(false); }
private InlineProcessor BuidProcessor() { var p = new WikiLinkParser(); var pr = new InlineProcessor(new StringBuilderCache(), new MarkdownDocument(), new InlineParserList(Enumerable.Empty <InlineParser>()), false); return(pr); }
public void DocumentOnProcessInlinesBegin_CreatesAndAddsALinkReferenceDefinitionForEachReferenceLinkableFlexiFigureBlock() { // Arrange const string dummyLinkLabelContent = "dummyLinkLabelContent"; const string dummyID = "dummyID"; const string dummyName = "dummyName"; FlexiFigureBlock dummyFlexiFigureBlock = CreateFlexiFigureBlock(name: dummyName, linkLabelContent: dummyLinkLabelContent, id: dummyID); InlineProcessor dummyInlineProcessor = MarkdigTypesFactory.CreateInlineProcessor(); dummyInlineProcessor.Document.SetData(FlexiFigureBlockFactory.REFERENCE_LINKABLE_FLEXI_FIGURE_BLOCKS_KEY, new List <FlexiFigureBlock> { dummyFlexiFigureBlock }); FlexiFigureBlockFactory testSubject = CreateFlexiFigureBlockFactory(); // Act testSubject.DocumentOnProcessInlinesBegin(dummyInlineProcessor, null); // Assert Dictionary <string, LinkReferenceDefinition> linkReferenceDefinitions = (dummyInlineProcessor.Document.GetData(typeof(LinkReferenceDefinitionGroup)) as LinkReferenceDefinitionGroup)?.Links; Assert.Single(linkReferenceDefinitions); LinkReferenceDefinition resultLinkReferenceDefinition = linkReferenceDefinitions.Values.First(); Assert.Equal(dummyLinkLabelContent, resultLinkReferenceDefinition.Label); Assert.Equal($"#{dummyID}", resultLinkReferenceDefinition.Url); Assert.Equal(dummyName, resultLinkReferenceDefinition.Title); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { bool matchFound = slice.MatchLowercase(matchingText); if (matchFound) { int inlineStart = processor.GetSourcePosition(slice.Start, out int line, out int column); processor.Inline = new MatchingTextInline { Span = { Start = inlineStart, End = inlineStart + matchingText.Length }, Line = line, Column = column, MatchingText = matchingText }; slice.Start = inlineStart + matchingText.Length; } return(matchFound); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { if (!ExtensionsHelper.MatchStart(ref slice, StartString, false)) { return(false); } else { if (slice.CurrentChar == '-') { slice.NextChar(); } } var includeFile = new InclusionInline(); string title = null, path = null; if (!ExtensionsHelper.MatchLink(ref slice, ref title, ref path)) { return(false); } includeFile.Title = title; includeFile.IncludedFilePath = path; processor.Inline = includeFile; return(true); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { if (slice.CurrentChar == '$' && slice.PeekChar(1) == '(') { slice.NextChar(); slice.NextChar(); int start = slice.Start; int end = start; while (slice.CurrentChar != ')') { end = slice.Start; slice.NextChar(); } processor.GetSourcePosition(slice.Start, out int line, out int column); processor.Inline = new VariableInline { Line = line, Column = column, VariableName = new StringSlice(slice.Text, start, end) }; slice.NextChar(); return(true); } return(false); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { // Hard line breaks are for separating inline content within a block. Neither syntax for hard line breaks works at the end of a paragraph or other block element: if (!(processor.Block is ParagraphBlock)) { return(false); } var startPosition = slice.Start; var hasDoubleSpacesBefore = slice.PeekCharExtra(-1).IsSpace() && slice.PeekCharExtra(-2).IsSpace(); slice.NextChar(); // Skip \n int line; int column; processor.Inline = new LineBreakInline { Span = { Start = processor.GetSourcePosition(startPosition, out line, out column) }, IsHard = EnableSoftAsHard || (slice.Start != 0 && hasDoubleSpacesBefore), Line = line, Column = column }; processor.Inline.Span.End = processor.Inline.Span.Start; return(true); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { var startPosition = processor.GetSourcePosition(slice.Start, out var line, out var column); if (!ExtensionsHelper.MatchStart(ref slice, StartString, false)) { return(false); } if (slice.CurrentChar == '-') { slice.NextChar(); } string title = null, path = null; if (!ExtensionsHelper.MatchLink(ref slice, ref title, ref path) || !ExtensionsHelper.MatchInclusionEnd(ref slice)) { return(false); } processor.Inline = new InclusionInline { Title = title, IncludedFilePath = path, Line = line, Column = column, Span = new SourceSpan(startPosition, processor.GetSourcePosition(slice.Start - 1)), IsClosed = true, }; return(true); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { // A tasklist is either // [ ] // or [x] or [X] if (!(processor.Block !.Parent is ListItemBlock listItemBlock)) { return(false); } var startingPosition = slice.Start; var c = slice.NextChar(); if (!c.IsSpace() && c != 'x' && c != 'X') { return(false); } if (slice.NextChar() != ']') { return(false); } // Skip last ] slice.SkipChar(); // Create the TaskList var taskItem = new TaskList() { Span = { Start = processor.GetSourcePosition(startingPosition, out int line, out int column) },
public override bool Match(InlineProcessor processor, ref StringSlice slice) { bool matchFound; char previous; matchFound = false; previous = slice.PeekCharExtra(-1); if (!previous.IsWhiteSpaceOrZero()) { return(false); } char current; int start; int end; slice.NextChar(); current = slice.CurrentChar; start = slice.Start; end = start; StringBuilder ep = new StringBuilder(); StringBuilder num = new StringBuilder(); while (current != ',') { end = slice.Start; ep.Append(current); current = slice.NextChar(); } current = slice.NextChar(); while (current != '}') { end = slice.Start; num.Append(current); current = slice.NextChar(); } current = slice.NextChar(); if (current.IsWhiteSpaceOrZero()) { int inlineStart; inlineStart = processor.GetSourcePosition(slice.Start, out int line, out int column); processor.Inline = new Caps() { Span = { Start = inlineStart, End = inlineStart + (end - start) + 1 }, Line = line, Column = column, CapEpisode = new StringSlice(ep.ToString()), CapNumber = new StringSlice(num.ToString()) }; matchFound = true; } return(matchFound); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { string match; // Previous char must be a space if (!slice.PeekCharExtra(-1).IsWhiteSpaceOrZero()) { return(false); } // Try to match an existing emoji var startPosition = slice.Start; if (!textMatchHelper.TryMatch(slice.Text, slice.Start, slice.Length, out match)) { return(false); } string emoji = match; if (EnableSmiley) { // If we have a smiley, we decode it to emoji if (!SmileyToEmoji.TryGetValue(match, out emoji)) { emoji = match; } } // Decode the eomji to unicode string unicode; if (!EmojiToUnicode.TryGetValue(emoji, out unicode)) { // Should not happen but in case return(false); } // Move the cursor to the character after the matched string slice.Start += match.Length; // Push the EmojiInline int line; int column; processor.Inline = new EmojiInline(unicode) { Span = { Start = processor.GetSourcePosition(startPosition, out line, out column), }, Line = line, Column = column, Match = match }; processor.Inline.Span.End = processor.Inline.Span.Start + match.Length - 1; return(true); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { // First, some definitions. // A delimiter run is a sequence of one or more delimiter characters that is not preceded or followed by the same delimiter character // The amount of delimiter characters in the delimiter run may exceed emphasisDesc.MaximumCount, as that is handeled in `ProcessEmphasis` var delimiterChar = slice.CurrentChar; var emphasisDesc = emphasisMap ![delimiterChar] !;
public override bool Match(InlineProcessor processor, ref StringSlice slice) { if (slice.Start != 0 && !slice.PeekCharExtra(-1).IsWhitespace()) { return(false); } string match; if (!_textMatchHelper.TryMatch(slice.Text, slice.Start, slice.Length, out match)) { return(false); } // Move the cursor to the character after the matched string slice.Start += match.Length; var builder = new StringBuilder(); while (slice.CurrentChar.IsDigit() && !slice.IsEmpty) { builder.Append(slice.CurrentChar); slice.Start++; } var index = builder.Length > 0 ? int.Parse(builder.ToString()) : 0; if (index == 0) { //If we failed to parse index, abort slice.Start -= builder.Length; slice.Start -= match.Length; return(false); } builder.Clear(); if (slice.CurrentChar == '(') { slice.Start++; while (slice.CurrentChar != ')' && !slice.IsEmpty) { builder.Append(slice.CurrentChar); slice.Start++; } if (!slice.IsEmpty) { slice.Start++; } } var extra = builder.ToString(); processor.Inline = new EntityLinkInline(match, index, extra); return(true); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { if (!slice.PeekCharExtra(-1).IsWhiteSpaceOrZero()) { return(false); //require whitespace/nothing before } var key = String.Empty; var issue = String.Empty; var current = slice.CurrentChar; //read as many uppercase characters as required - project key while (current.IsAlphaUpper()) { key += current; current = slice.NextChar(); } //require a '-' between key and issue number if (!current.Equals('-')) { return(false); } current = slice.NextChar(); //read as many numbers as required - issue number while (current.IsDigit()) { issue += current; current = slice.NextChar(); } if (!current.IsWhiteSpaceOrZero()) //must be followed by whitespace { return(false); } int line; int column; processor.Inline = new JiraLink() //create the link at the relevant position { Span = { Start = processor.GetSourcePosition(slice.Start, out line, out column) }, Line = line, Column = column, Issue = issue, Key = key }; processor.Inline.Span.End = processor.Inline.Span.Start + issue.Length + key.Length + 1; //+1 for the '-' return(true); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { if (!ExtensionsHelper.MatchStart(ref slice, StartString, false)) { return(false); } var href = StringBuilderCache.Local(); var c = slice.CurrentChar; var saved = slice; var startChar = '\0'; int line; int column; if (c == '\'' || c == '"') { startChar = c; c = slice.NextChar(); } while (c != startChar && c != '>') { href.Append(c); c = slice.NextChar(); } if (startChar != '\0') { if (c != startChar) { return(false); } c = slice.NextChar(); } if (c != '>') { return(false); } slice.NextChar(); var xrefInline = new XrefInline { Href = href.ToString().Trim(), Span = new SourceSpan(processor.GetSourcePosition(saved.Start, out line, out column), processor.GetSourcePosition(slice.Start - 1)), Line = line, Column = column }; var htmlAttributes = xrefInline.GetAttributes(); htmlAttributes.AddPropertyIfNotExist("data-throw-if-not-resolved", "True"); processor.Inline = xrefInline; return(true); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { var startPosition = slice.Start; // Go to escape character var c = slice.NextChar(); int line; int column; if (c.IsAsciiPunctuation()) { processor.Inline = new LiteralInline() { Content = new StringSlice(slice.Text, slice.Start, slice.Start), Span = { Start = processor.GetSourcePosition(startPosition, out line, out column) }, Line = line, Column = column, IsFirstCharacterEscaped = true, }; processor.Inline.Span.End = processor.Inline.Span.Start + 1; slice.SkipChar(); return(true); } // A backslash at the end of the line is a [hard line break]: if (c == '\n' || c == '\r') { var newLine = c == '\n' ? NewLine.LineFeed : NewLine.CarriageReturn; if (c == '\r' && slice.PeekChar() == '\n') { newLine = NewLine.CarriageReturnLineFeed; } var inline = new LineBreakInline() { IsHard = true, IsBackslash = true, Span = { Start = processor.GetSourcePosition(startPosition, out line, out column) }, Line = line, Column = column, }; processor.Inline = inline; if (processor.TrackTrivia) { inline.NewLine = newLine; } inline.Span.End = inline.Span.Start + 1; slice.SkipChar(); // Skip \n or \r alone if (newLine == NewLine.CarriageReturnLineFeed) { slice.SkipChar(); // Skip \r\n } return(true); } return(false); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { // Allow preceding whitespace or `(` var pc = slice.PeekCharExtra(-1); if (!pc.IsWhiteSpaceOrZero() && pc != '(') { return(false); } var current = slice.CurrentChar; var startKey = slice.Start; var endKey = slice.Start; //read as many uppercase characters as required - project key while (current.IsAlphaUpper()) { endKey = slice.Start; current = slice.NextChar(); } //require a '-' between key and issue number if (!current.Equals('-')) { return(false); } current = slice.NextChar(); // skip - //read as many numbers as required - issue number if (!current.IsDigit()) { return(false); } var startIssue = slice.Start; var endIssue = slice.Start; while (current.IsDigit()) { endIssue = slice.Start; current = slice.NextChar(); } if (!current.IsWhiteSpaceOrZero() && current != ')') //can be followed only by a whitespace or `)` { return(false); } var jiraLink = new JiraLink() //create the link at the relevant position { Span = { Start = processor.GetSourcePosition(slice.Start, out int line, out int column) },
public override bool Match(InlineProcessor processor, ref StringSlice slice) { HtmlAttributes attributes; var startPosition = slice.Start; if (TryParse(ref slice, out attributes)) { var inline = processor.Inline; // If the current object to attach is either a literal or delimiter // try to find a suitable parent, otherwise attach the html attributes to the block if (inline is LiteralInline) { while (true) { inline = inline.Parent; if (!(inline is DelimiterInline)) { break; } } } var objectToAttach = inline == null || inline == processor.Root ? (MarkdownObject)processor.Block : inline; // If the current block is a Paragraph, but only the HtmlAttributes is used, // Try to attach the attributes to the following block var paragraph = objectToAttach as ParagraphBlock; if (paragraph != null && paragraph.Inline.FirstChild == null && processor.Inline == null && slice.IsEmptyOrWhitespace()) { var parent = paragraph.Parent; var indexOfParagraph = parent.IndexOf(paragraph); if (indexOfParagraph + 1 < parent.Count) { objectToAttach = parent[indexOfParagraph + 1]; // We can remove the paragraph as it is empty paragraph.RemoveAfterProcessInlines = true; } } var currentHtmlAttributes = objectToAttach.GetAttributes(); attributes.CopyTo(currentHtmlAttributes, true, false); // Update the position of the attributes int line; int column; currentHtmlAttributes.Span.Start = processor.GetSourcePosition(startPosition, out line, out column); currentHtmlAttributes.Line = line; currentHtmlAttributes.Column = column; currentHtmlAttributes.Span.End = currentHtmlAttributes.Span.Start + slice.Start - startPosition - 1; // We don't set the processor.Inline as we don't want to add attach attributes to a particular entity return(true); } return(false); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { // A tasklist is either // [ ] // or [x] or [X] var listItemBlock = processor.Block.Parent as ListItemBlock; if (listItemBlock == null) { return(false); } var startingPosition = slice.Start; var c = slice.NextChar(); if (!c.IsSpace() && c != 'x' && c != 'X') { return(false); } if (slice.NextChar() != ']') { return(false); } // Skip last ] slice.NextChar(); // Create the TaskList int line; int column; var taskItem = new TaskList() { Span = { Start = processor.GetSourcePosition(startingPosition, out line, out column) }, Line = line, Column = column, Checked = !c.IsSpace() }; taskItem.Span.End = taskItem.Span.Start + 2; processor.Inline = taskItem; // Add proper class for task list if (!string.IsNullOrEmpty(ListItemClass)) { listItemBlock.GetAttributes().AddClass(ListItemClass); } var listBlock = (ListBlock)listItemBlock.Parent; if (!string.IsNullOrEmpty(ListClass)) { listBlock.GetAttributes().AddClass(ListClass); } return(true); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { bool matchFound; char next; matchFound = false; next = slice.PeekCharExtra(1); if (next == '<') { char current; int start; int end; slice.NextChar(); slice.NextChar(); // skip the opening pair current = slice.CurrentChar; start = slice.Start; end = start; while (current != '\0' && current != '>') { end++; current = slice.NextChar(); } if (end > start && current == '>' && slice.PeekCharExtra(1) == '>') { int inlineStart; end--; inlineStart = processor.GetSourcePosition(slice.Start, out int line, out int column); processor.Inline = new KeyboardInline { Span = { Start = inlineStart, End = inlineStart + (end - start) }, Line = line, Column = column, Text = new StringSlice(slice.Text, start, end) }; slice.NextChar(); slice.NextChar(); // skip the closing characters matchFound = true; } } return(matchFound); }