/
GlobalizationExtension.cs
122 lines (105 loc) · 3.72 KB
/
GlobalizationExtension.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using Markdig.Extensions.Tables;
using Markdig.Extensions.TaskLists;
using Markdig.Helpers;
using Markdig.Renderers;
using Markdig.Renderers.Html;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
using System.Collections.Generic;
using System.Diagnostics;
namespace Markdig.Extensions.Globalization
{
/// <summary>
/// Extension to add support for RTL content.
/// </summary>
public class GlobalizationExtension : IMarkdownExtension
{
public void Setup(MarkdownPipelineBuilder pipeline)
{
// Make sure we don't have a delegate twice
pipeline.DocumentProcessed -= Pipeline_DocumentProcessed;
pipeline.DocumentProcessed += Pipeline_DocumentProcessed;
}
private void Pipeline_DocumentProcessed(MarkdownDocument document)
{
foreach (var node in document.Descendants())
{
if (node is TableRow || node is TableCell || node is ListItemBlock)
continue;
if (ShouldBeRightToLeft(node))
{
var attributes = node.GetAttributes();
attributes.AddPropertyIfNotExist("dir", "rtl");
if (node is Table)
{
attributes.AddPropertyIfNotExist("align", "right");
}
}
}
}
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
{
}
private static bool ShouldBeRightToLeft(MarkdownObject item)
{
if (item is IEnumerable<MarkdownObject> container)
{
foreach (var child in container)
{
// TaskList items contain an "X", which will cause
// the function to always return false.
if (child is TaskList)
continue;
return ShouldBeRightToLeft(child);
}
}
else if (item is LeafBlock leaf)
{
return ShouldBeRightToLeft(leaf.Inline!);
}
else if (item is LiteralInline literal)
{
return StartsWithRtlCharacter(literal.Content);
}
foreach (var paragraph in item.Descendants<ParagraphBlock>())
{
foreach (var inline in paragraph.Inline!)
{
if (inline is LiteralInline literal)
{
return StartsWithRtlCharacter(literal.Content);
}
}
}
return false;
}
private static bool StartsWithRtlCharacter(StringSlice slice)
{
for (int i = slice.Start; i <= slice.End; i++)
{
if (slice[i] < 128)
{
continue;
}
int rune;
if (CharHelper.IsHighSurrogate(slice[i]) && i < slice.End && CharHelper.IsLowSurrogate(slice[i + 1]))
{
Debug.Assert(char.IsSurrogatePair(slice[i], slice[i + 1]));
rune = char.ConvertToUtf32(slice[i], slice[i + 1]);
}
else
{
rune = slice[i];
}
if (CharHelper.IsRightToLeft(rune))
return true;
if (CharHelper.IsLeftToRight(rune))
return false;
}
return false;
}
}
}