Handle correctly pipe delimiters inside a link

This commit is contained in:
Alexandre Mutel
2016-03-05 20:43:06 +09:00
parent 3132f27b2d
commit f5d99cd2bf
7 changed files with 144 additions and 33 deletions

View File

@@ -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>
````````````````````````````````

View File

@@ -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
//

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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.