mirror of
https://github.com/xoofx/markdig.git
synced 2026-10-08 06:38:39 +00:00
Handle correctly pipe delimiters inside a link
This commit is contained in:
@@ -377,3 +377,29 @@ a <a href="" title="|"></a> | b
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Rule #8**
|
||||
|
||||
The character `|` inside a link label is not recognize as a column delimiter
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-- | --
|
||||
[This is a link with a | inside the label](http://google.com) | 1
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="http://google.com">This is a link with a | inside the label</a></td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
@@ -16776,6 +16776,43 @@ namespace Textamina.Markdig.Tests
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 16, "Extensions Pipe Table");
|
||||
TestParser.TestSpec("a <a href=\"\" title=\"|\"></a> | b\n-- | --\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a <a href=\"\" title=\"|\"></a></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables");
|
||||
}
|
||||
}
|
||||
// **Rule #8**
|
||||
//
|
||||
// Links labels are escaping `|`
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsPipeTable
|
||||
{
|
||||
[Test]
|
||||
public void Example017()
|
||||
{
|
||||
// Example 17
|
||||
// Section: Extensions Pipe Table
|
||||
//
|
||||
// The following CommonMark:
|
||||
// a | b
|
||||
// -- | --
|
||||
// [This is a link with a | inside the label](http://google.com) | 1
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td><a href="http://google.com">This is a link with a | inside the label</a></td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 17, "Extensions Pipe Table");
|
||||
TestParser.TestSpec("a | b\n-- | --\n[This is a link with a | inside the label](http://google.com) | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><a href=\"http://google.com\">This is a link with a | inside the label</a></td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables");
|
||||
}
|
||||
}
|
||||
// # Extensions
|
||||
//
|
||||
|
||||
@@ -109,11 +109,81 @@ namespace Textamina.Markdig.Extensions.Tables
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ProcessDelimiters(InlineParserState state, Inline root, Inline lastChild, int delimiterProcessorIndex)
|
||||
public bool ProcessDelimiters(InlineParserState state, Inline root, Inline lastChild, int delimiterProcessorIndex, bool isFinalProcessing)
|
||||
{
|
||||
// Continue
|
||||
var container = root as ContainerInline;
|
||||
var tableState = state.ParserStates[Index] as TableState;
|
||||
|
||||
// If the delimiters are being processed by an image link, we need to transform them back to literals
|
||||
if (!isFinalProcessing)
|
||||
{
|
||||
if (container == null || tableState == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var child = container.LastChild;
|
||||
List<PiprTableDelimiterInline> delimitersToRemove = null;
|
||||
|
||||
while (child != null)
|
||||
{
|
||||
var pipeDelimiter = child as PiprTableDelimiterInline;
|
||||
if (pipeDelimiter != null)
|
||||
{
|
||||
if (delimitersToRemove == null)
|
||||
{
|
||||
delimitersToRemove = new List<PiprTableDelimiterInline>();
|
||||
}
|
||||
delimitersToRemove.Add(pipeDelimiter);
|
||||
}
|
||||
|
||||
if (child == lastChild)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var subContainer = child as ContainerInline;
|
||||
child = subContainer?.LastChild;
|
||||
}
|
||||
|
||||
// If we have found any delimiters, transform them to literals
|
||||
if (delimitersToRemove != null)
|
||||
{
|
||||
bool leftIsDelimiter = false;
|
||||
bool rightIsDelimiter = false;
|
||||
for (int i = 0; i < delimitersToRemove.Count; i++)
|
||||
{
|
||||
var pipeDelimiter = delimitersToRemove[i];
|
||||
pipeDelimiter.ReplaceBy(new LiteralInline() {Content = new StringSlice("|"), IsClosed = true});
|
||||
|
||||
// Check that the pipe that is being removed is not going to make a line without pipe delimiters
|
||||
var tableDelimiters = tableState.ColumnAndLineDelimiters;
|
||||
var delimiterIndex = tableDelimiters.IndexOf(pipeDelimiter);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
leftIsDelimiter = delimiterIndex > 0 && tableDelimiters[delimiterIndex - 1] is PiprTableDelimiterInline;
|
||||
}
|
||||
else if (i + 1 == delimitersToRemove.Count)
|
||||
{
|
||||
rightIsDelimiter = delimiterIndex + 1 < tableDelimiters.Count &&
|
||||
tableDelimiters[delimiterIndex + 1] is PiprTableDelimiterInline;
|
||||
}
|
||||
// Remove this delimiter from the table state
|
||||
tableState.ColumnAndLineDelimiters.Remove(pipeDelimiter);
|
||||
}
|
||||
|
||||
// If we didn't have any delimiter before and after the delimiters we jsut removed, we mark the state of the current line as no pipe
|
||||
if (!leftIsDelimiter && !rightIsDelimiter)
|
||||
{
|
||||
tableState.LineHasPipe = false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Continue
|
||||
if (tableState == null || container == null || tableState.IsInvalidTable || !tableState.LineHasPipe || tableState.LineIndex != state.LocalLineIndex)
|
||||
{
|
||||
return true;
|
||||
@@ -258,7 +328,7 @@ namespace Textamina.Markdig.Extensions.Tables
|
||||
{
|
||||
foreach (var cell in cells)
|
||||
{
|
||||
state.ProcessDelimiters(i + 1, cell.Inline);
|
||||
state.ProcessDelimiters(i + 1, cell.Inline, null, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,9 @@ namespace Textamina.Markdig.Parsers
|
||||
/// <param name="root">The root inline.</param>
|
||||
/// <param name="lastChild">The last child.</param>
|
||||
/// <param name="delimiterProcessorIndex">Index of this delimiter processor.</param>
|
||||
/// <param name="isFinalProcessing"></param>
|
||||
/// <returns><c>true</c> to continue to the next delimiter processor;
|
||||
/// <c>false</c> to stop the process (in case a processor is perfoming sub-sequent processor itself)</returns>
|
||||
bool ProcessDelimiters(InlineParserState state, Inline root, Inline lastChild, int delimiterProcessorIndex);
|
||||
bool ProcessDelimiters(InlineParserState state, Inline root, Inline lastChild, int delimiterProcessorIndex, bool isFinalProcessing);
|
||||
}
|
||||
}
|
||||
@@ -218,7 +218,7 @@ namespace Textamina.Markdig.Parsers
|
||||
}
|
||||
|
||||
// Process all delimiters
|
||||
ProcessDelimiters(0, Root);
|
||||
ProcessDelimiters(0, Root, null, true);
|
||||
|
||||
//TransformDelimitersToLiterals();
|
||||
|
||||
@@ -230,12 +230,12 @@ namespace Textamina.Markdig.Parsers
|
||||
}
|
||||
}
|
||||
|
||||
public void ProcessDelimiters(int startingIndex, Inline root, Inline lastChild = null)
|
||||
public void ProcessDelimiters(int startingIndex, Inline root, Inline lastChild, bool isFinalProcessing)
|
||||
{
|
||||
for (int i = startingIndex; i < Parsers.DelimiterProcessors.Length; i++)
|
||||
{
|
||||
var delimiterProcessor = Parsers.DelimiterProcessors[i];
|
||||
if (!delimiterProcessor.ProcessDelimiters(this, root, lastChild, i))
|
||||
if (!delimiterProcessor.ProcessDelimiters(this, root, lastChild, i, isFinalProcessing))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Textamina.Markdig.Parsers.Inlines
|
||||
OpeningCharacters = new[] { '*', '_' };
|
||||
}
|
||||
|
||||
public bool ProcessDelimiters(InlineParserState state, Inline root, Inline lastChild, int delimiterProcessorIndex)
|
||||
public bool ProcessDelimiters(InlineParserState state, Inline root, Inline lastChild, int delimiterProcessorIndex, bool isFinalProcessing)
|
||||
{
|
||||
var container = root as ContainerInline;
|
||||
if (container == null)
|
||||
|
||||
@@ -13,8 +13,6 @@ namespace Textamina.Markdig.Parsers.Inlines
|
||||
/// <seealso cref="Textamina.Markdig.Parsers.InlineParser" />
|
||||
public class LinkInlineParser : InlineParser
|
||||
{
|
||||
private int emphasisInlineDelimiterProcessorIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LinkInlineParser"/> class.
|
||||
/// </summary>
|
||||
@@ -23,21 +21,6 @@ namespace Textamina.Markdig.Parsers.Inlines
|
||||
OpeningCharacters = new[] {'[', ']', '!'};
|
||||
}
|
||||
|
||||
public override void Initialize(InlineParserState state)
|
||||
{
|
||||
// Look for emphasis delimiter processor
|
||||
emphasisInlineDelimiterProcessorIndex = -1;
|
||||
for (int i = 0; i < state.Parsers.DelimiterProcessors.Length; i++)
|
||||
{
|
||||
var delimiters = state.Parsers.DelimiterProcessors[i];
|
||||
if (delimiters is EmphasisInlineParser)
|
||||
{
|
||||
emphasisInlineDelimiterProcessorIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Match(InlineParserState state, ref StringSlice slice)
|
||||
{
|
||||
// The following methods are inspired by the "An algorithm for parsing nested emphasis and links"
|
||||
@@ -151,10 +134,7 @@ namespace Textamina.Markdig.Parsers.Inlines
|
||||
link.IsClosed = true;
|
||||
|
||||
// Process emphasis delimiters
|
||||
if (emphasisInlineDelimiterProcessorIndex >= 0)
|
||||
{
|
||||
state.ProcessDelimiters(emphasisInlineDelimiterProcessorIndex, link);
|
||||
}
|
||||
state.ProcessDelimiters(0, link, null, false);
|
||||
|
||||
state.Inline = link;
|
||||
isValidLink = true;
|
||||
@@ -221,10 +201,7 @@ namespace Textamina.Markdig.Parsers.Inlines
|
||||
inlineState.Inline = link;
|
||||
|
||||
// Process emphasis delimiters
|
||||
if (emphasisInlineDelimiterProcessorIndex >= 0)
|
||||
{
|
||||
inlineState.ProcessDelimiters(emphasisInlineDelimiterProcessorIndex, link);
|
||||
}
|
||||
inlineState.ProcessDelimiters(0, link, null, false);
|
||||
|
||||
// If we have a link (and not an image),
|
||||
// we also set all [ delimiters before the opening delimiter to inactive.
|
||||
|
||||
Reference in New Issue
Block a user