3using System.Collections;
4using System.Collections.Generic;
6using System.Reflection;
8using System.Text.RegularExpressions;
9using System.Threading.Tasks;
56 internal static readonly Regex endOfHeader =
new Regex(
@"\n\s*\n", RegexOptions.Multiline | RegexOptions.Compiled);
57 internal static readonly Regex scriptHeader =
new Regex(
@"^(?'Tag'(([Ss][Cc][Rr][Ii][Pp][Tt])|([Ii][Nn][Ii][Tt]))):\s*(?'ScriptFile'[^\r\n]*)", RegexOptions.Multiline | RegexOptions.Compiled);
59 private readonly List<KeyValuePair<AsyncMarkdownProcessing, object>> asyncTasks =
new List<KeyValuePair<AsyncMarkdownProcessing, object>>();
60 private readonly Dictionary<string, Multimedia> references =
new Dictionary<string, Multimedia>();
61 private readonly Dictionary<string, KeyValuePair<string, bool>[]> metaData =
new Dictionary<string, KeyValuePair<string, bool>[]>();
62 private Dictionary<string, int> footnoteNumberByKey =
null;
63 private Dictionary<string, Footnote> footnotes =
null;
64 private SortedDictionary<int, string> toInsert =
null;
65 private readonly Type[] transparentExceptionTypes;
66 private List<string> footnoteOrder =
null;
67 private readonly LinkedList<MarkdownElement> elements;
68 private readonly List<Header> headers =
new List<Header>();
70 private string markdownText;
71 private string fileName =
string.Empty;
72 private string resourceName =
string.Empty;
73 private string url =
string.Empty;
77 private int lastFootnote = 0;
78 private bool syntaxHighlighting =
false;
79 private bool includesTableOfContents =
false;
80 private bool isDynamic =
false;
81 private bool? allowScriptTag =
null;
82 private object tag =
null;
136 this.markdownText =
MarkdownText?.Replace(
"\r\n",
"\n").Replace(
'\r',
'\n') ??
string.Empty;
145 List<Block> Blocks = ParseTextToBlocks(this.markdownText);
146 List<KeyValuePair<string, bool>> Values =
new List<KeyValuePair<string, bool>>();
148 KeyValuePair<string, bool>[] Prev;
152 int End = Blocks.Count - 1;
158 for (i = Block.Start; i <= Block.End; i++)
165 if (
string.IsNullOrEmpty(Key))
168 Values.Add(
new KeyValuePair<string, bool>(s.Trim(), s.EndsWith(
" ")));
172 s2 = s.Substring(0, j).TrimEnd().ToUpper();
174 if (
string.IsNullOrEmpty(Key))
176 foreach (
char ch
in s2)
178 if (!
char.IsLetter(ch) && !
char.IsWhiteSpace(ch))
190 if (this.metaData.TryGetValue(Key, out Prev))
191 Values.InsertRange(0, Prev);
193 this.metaData[Key] = Values.ToArray();
198 Values.Add(
new KeyValuePair<string, bool>(s.Substring(j + 1).Trim(), s.EndsWith(
" ")));
202 if (!
string.IsNullOrEmpty(Key))
204 if (this.metaData.TryGetValue(Key, out Prev))
205 Values.InsertRange(0, Prev);
206 else if (
string.
Compare(Key,
"Login",
true) == 0)
207 this.isDynamic =
true;
209 this.metaData[Key] = Values.ToArray();
214 this.elements = this.ParseBlocks(Blocks, Start, End);
216 if (!(this.toInsert is
null))
218 foreach (KeyValuePair<int, string> P
in this.toInsert)
219 this.markdownText = this.markdownText.Insert(P.Key, P.Value);
226 [Obsolete(
"Use GenerateMarkdown() instead.")]
248 Match M = endOfHeader.Match(Markdown);
252 string Header = Markdown.Substring(0, M.Index);
256 foreach (
string Row
in Rows)
259 if (
string.IsNullOrEmpty(s))
262 if (s.IndexOf(
':') < 0)
319 bool UsesImplicitPrint =
false;
320 bool HasImplicitPrint =
false;
322 if (!
string.IsNullOrEmpty(
FileName))
324 Match M = endOfHeader.Match(Markdown);
327 s2 = Markdown.Substring(0, M.Index);
329 foreach (Match M2
in scriptHeader.Matches(s2))
333 string Tag = M2.Groups[
"Tag"].Value.ToUpper();
334 string FileName2 = M2.Groups[
"ScriptFile"].Value;
356 if (!(Prohibited is
null))
357 throw new UnauthorizedAccessException(
"Expression not permitted: " + Prohibited.
SubExpression);
371 i = Markdown.IndexOf(
"{{");
375 j = Markdown.IndexOf(
"}}", i + 2);
379 Script = Markdown.Substring(i + 2, j - i - 2);
380 Markdown = Markdown.Remove(i, j - i + 2);
389 if (!(Prohibited is
null))
390 throw new UnauthorizedAccessException(
"Expression not permitted: " + Prohibited.
SubExpression);
401 HasImplicitPrint =
true;
403 if (HasImplicitPrint)
405 UsesImplicitPrint =
true;
412 StringBuilder sb =
new StringBuilder();
414 Variables.ConsoleOut =
new StringWriter(sb);
415 Variables.Printer = PrintMarkdown;
423 Variables.ConsoleOut = Bak;
424 Variables.Printer = PrinterBak;
430 Result = sb.ToString();
439 StringBuilder sb =
new StringBuilder();
441 sb.AppendLine(
"<font class=\"error\">");
443 if (ex is AggregateException ex2)
445 foreach (Exception ex3
in ex2.InnerExceptions)
453 sb.AppendLine(
"</p>");
465 sb.AppendLine(
"</font>");
467 Result = sb.ToString();
470 if (!(Result is
null))
472 if (!(Result is
string s3))
473 s3 = await PrintMarkdown(Result,
Variables);
475 Markdown = Markdown.Insert(i, s3);
479 i = Markdown.IndexOf(
"{{", i);
482 return new KeyValuePair<string, bool>(Markdown,
IsDynamic);
490 if (Value.GetType().GetTypeInfo().IsValueType || Value is
string)
491 return Value.ToString();
493 if (Value is XmlDocument ||
500 Value is Exception ||
511 return Value.ToString();
514 internal void CheckException(Exception ex)
516 CheckException(ex, this.transparentExceptionTypes);
521 TypeInfo ExceptionType = ex.GetType().GetTypeInfo();
525 if (T.GetTypeInfo().IsAssignableFrom(ExceptionType))
526 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw();
530 private LinkedList<MarkdownElement> ParseBlocks(List<Block> Blocks)
532 return this.ParseBlocks(Blocks, 0, Blocks.Count - 1);
535 private LinkedList<MarkdownElement> ParseBlocks(List<Block> Blocks,
int StartBlock,
int EndBlock)
537 LinkedList<MarkdownElement>
Elements =
new LinkedList<MarkdownElement>();
538 LinkedList<MarkdownElement> Content;
539 List<Block> AlignedBlocks;
544 string InitialSectionSeparator =
null;
549 int InitialNrColumns = 1;
550 bool HasSections =
false;
552 for (BlockIndex = StartBlock; BlockIndex <= EndBlock; BlockIndex++)
554 Block = Blocks[BlockIndex];
556 if (Block.Indent > 0)
560 while (i <= EndBlock && (j = Blocks[i].Indent) > 0)
567 if (i == BlockIndex + 1)
568 Elements.AddLast(
new CodeBlock(
this, Block.Rows, Block.Start, Block.End, c - 1));
571 List<string>
CodeBlock =
new List<string>();
573 while (BlockIndex < i)
578 Block = Blocks[BlockIndex++];
580 if (Block.Indent == c)
582 for (j = Block.Start; j <= Block.End; j++)
587 s =
new string(
'\t', Block.Indent - c);
588 for (j = Block.Start; j <= Block.End; j++)
598 else if (Block.IsPrefixedBy(
"```",
false))
600 s = Block.Rows[Block.Start];
602 foreach (
char ch
in s)
610 s = s.Substring(0, i);
613 while (i <= EndBlock &&
614 (!(Block = Blocks[i]).Rows[Block.End].StartsWith(s) ||
615 (i == BlockIndex && Block.Start == Block.End)))
620 List<string> Code =
new List<string>();
621 bool Complete =
true;
629 for (j = BlockIndex; j <= i; j++)
633 Index = Block.Start + 1;
636 Code.Add(
string.Empty);
640 if (j == i && Complete)
647 Code.Add(Block.Rows[Index]);
652 Block = Blocks[BlockIndex];
653 s = Block.Rows[Block.Start].Substring(3).Trim(
'`',
' ',
'\t');
657 if (s.StartsWith(
"base64", StringComparison.CurrentCultureIgnoreCase))
661 StringBuilder sb =
new StringBuilder();
663 foreach (
string Row
in Code)
666 byte[] Bin = Convert.FromBase64String(sb.ToString());
667 s2 = Encoding.UTF8.GetString(Bin);
669 Rows = s2.Replace(
"\r\n",
"\n").Replace(
"\r",
"\n").Split(
'\n');
687 this.syntaxHighlighting =
true;
694 if (Block.IsPrefixedBy(
">",
false))
696 if (Block.IsSuffixedBy(
"<<") && Block.IsPrefixedBy(
">>",
false))
698 AlignedBlocks = Block.RemovePrefixAndSuffix(
">>", 2,
"<<");
700 while (BlockIndex < EndBlock &&
701 (NextBlock = Blocks[BlockIndex + 1]).IsPrefixedBy(
">>",
false) &&
702 NextBlock.IsSuffixedBy(
"<<"))
705 AlignedBlocks.AddRange(NextBlock.RemovePrefixAndSuffix(
">>", 2,
"<<"));
708 Content = this.ParseBlocks(AlignedBlocks);
715 else if (Block.IsSuffixedBy(
">>"))
717 AlignedBlocks = Block.RemoveSuffix(
">>");
719 while (BlockIndex < EndBlock &&
720 (NextBlock = Blocks[BlockIndex + 1]).IsSuffixedBy(
">>"))
723 AlignedBlocks.AddRange(NextBlock.RemoveSuffix(
">>"));
726 Content = this.ParseBlocks(AlignedBlocks);
735 Content = this.ParseBlocks(Block.RemovePrefix(
">", 2));
745 else if (Block.IsPrefixedBy(
"<<",
false))
747 if (Block.IsSuffixedBy(
">>"))
749 AlignedBlocks = Block.RemovePrefixAndSuffix(
"<<", 2,
">>");
751 while (BlockIndex < EndBlock &&
752 (NextBlock = Blocks[BlockIndex + 1]).IsPrefixedBy(
"<<",
false) &&
753 NextBlock.IsSuffixedBy(
">>"))
756 AlignedBlocks.AddRange(NextBlock.RemovePrefixAndSuffix(
"<<", 2,
">>"));
759 Content = this.ParseBlocks(AlignedBlocks);
768 AlignedBlocks = Block.RemovePrefix(
"<<", 2);
770 while (BlockIndex < EndBlock &&
771 (NextBlock = Blocks[BlockIndex + 1]).IsPrefixedBy(
"<<",
false))
774 AlignedBlocks.AddRange(NextBlock.RemovePrefix(
"<<", 2));
777 Content = this.ParseBlocks(AlignedBlocks);
787 else if (Block.IsSuffixedBy(
">>"))
789 Content = this.ParseBlocks(Block.RemoveSuffix(
">>"));
798 else if (Block.IsPrefixedBy(
"+>",
false))
800 Content = this.ParseBlocks(Block.RemovePrefix(
"+>", 3));
809 else if (Block.IsPrefixedBy(
"->",
false))
811 Content = this.ParseBlocks(Block.RemovePrefix(
"->", 3));
820 else if (Block.IsPrefixedBy(
"//",
false))
822 string[] Comment =
new string[Block.End - Block.Start + 1];
824 for (i = Block.Start; i <= Block.End; i++)
825 Comment[i] = Block.Rows[i].Substring(2);
830 else if (Block.End == Block.Start && (IsUnderline(Block.Rows[0],
'-',
true,
true) || IsUnderline(Block.Rows[0],
'*',
true,
true)))
835 else if (Block.End == Block.Start && (IsUnderline(Block.Rows[0],
'=',
true,
false)))
837 int NrColumns = Block.Rows[0].Split(whiteSpace, StringSplitOptions.RemoveEmptyEntries).Length;
842 InitialNrColumns = NrColumns;
843 InitialSectionSeparator = Block.Rows[0];
849 else if (Block.End == Block.Start && IsUnderline(Block.Rows[0],
'~',
false,
false))
854 else if (Block.IsPrefixedBy(s2 =
"*",
true) ||
855 Block.IsPrefixedBy(s2 =
"+",
true) ||
856 Block.IsPrefixedBy(s2 =
"-",
true))
858 LinkedList<Block> Segments =
null;
862 for (d = Block.Start + 1; d <= c; d++)
865 if (IsPrefixedBy(s, s2,
true))
867 if (Segments is
null)
868 Segments =
new LinkedList<Block>();
870 Segments.AddLast(
new Block(Block.Rows, Block.Positions, 0, i, d - 1));
875 Segments?.AddLast(
new Block(Block.Rows, Block.Positions, 0, i, c));
877 LinkedList<MarkdownElement> Items;
880 if (Segments is
null)
882 List<Block> SubBlocks = Block.RemovePrefix(s2, 4);
884 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 1)
888 SubBlocks.Add(Block);
891 Items = this.ParseBlocks(SubBlocks);
901 Items =
new LinkedList<MarkdownElement>();
904 foreach (Block Segment
in Segments)
906 foreach (Block SegmentItem
in Segment.RemovePrefix(s2, 4))
909 Items.AddLast(LastItem);
919 if (!(LastItem is
null))
922 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 0)
930 Items = this.ParseBlocks(Blocks, i + 1, BlockIndex);
934 if (LastItemChildren.IsBlockElement)
935 LastItemChildren.AddChildren(Items);
938 Items.AddFirst(
new Paragraph(
this, LastItemChildren.Children,
true));
945 Items.AddFirst(LastItem.
Child);
956 else if (Block.IsPrefixedBy(
"#.",
true))
958 LinkedList<Tuple<int, bool, Block>> Segments =
null;
962 bool Explicit =
false;
964 for (d = Block.Start + 1; d <= c; d++)
967 if (IsPrefixedByNumber(s, out j))
969 if (Segments is
null)
970 Segments =
new LinkedList<Tuple<int, bool, Block>>();
972 Segments.AddLast(
new Tuple<int, bool, Block>(Index2, Explicit,
new Block(Block.Rows, Block.Positions, 0, i, d - 1)));
977 else if (IsPrefixedBy(s,
"#.",
true))
979 if (Segments is
null)
980 Segments =
new LinkedList<Tuple<int, bool, Block>>();
982 Segments.AddLast(
new Tuple<int, bool, Block>(Index2, Explicit,
new Block(Block.Rows, Block.Positions, 0, i, d - 1)));
989 Segments?.AddLast(
new Tuple<int, bool, Block>(Index2, Explicit,
new Block(Block.Rows, Block.Positions, 0, i, c)));
991 LinkedList<MarkdownElement> Items;
994 if (Segments is
null)
996 List<Block> SubBlocks = Block.RemovePrefix(
"#.", 4);
998 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 1)
1002 SubBlocks.Add(Block);
1005 Items = this.ParseBlocks(SubBlocks);
1015 Items =
new LinkedList<MarkdownElement>();
1018 foreach (Tuple<int, bool, Block> Segment
in Segments)
1020 s = Segment.Item2 ? Segment.Item1.
ToString() +
"." :
"#.";
1021 foreach (Block SegmentItem
in Segment.Item3.RemovePrefix(s, Math.Max(4, s.Length + 2)))
1023 LastItem =
new NumberedItem(
this, Segment.Item1, Segment.Item2,
1024 new NestedBlock(
this, this.ParseBlock(SegmentItem)));
1026 Items.AddLast(LastItem);
1036 if (!(LastItem is
null))
1039 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 0)
1047 Items = this.ParseBlocks(Blocks, i + 1, BlockIndex);
1051 if (LastItemChildren.IsBlockElement)
1052 LastItemChildren.AddChildren(Items);
1055 Items.AddFirst(
new Paragraph(
this, LastItemChildren.Children,
true));
1062 Items.AddFirst(LastItem.
Child);
1073 else if (Block.IsPrefixedBy(s2 =
"[ ]",
true) ||
1074 Block.IsPrefixedBy(s2 =
"[x]",
true) ||
1075 Block.IsPrefixedBy(s2 =
"[X]",
true))
1077 LinkedList<Tuple<Block, string, int>> Segments =
null;
1078 int CheckPosition = Block.Positions[0] + 1;
1083 for (d = Block.Start + 1; d <= c; d++)
1086 if (IsPrefixedBy(s, s3 =
"[ ]",
true) ||
1087 IsPrefixedBy(s, s3 =
"[x]",
true) ||
1088 IsPrefixedBy(s, s3 =
"[X]",
true))
1090 if (Segments is
null)
1091 Segments =
new LinkedList<Tuple<Block, string, int>>();
1093 Segments.AddLast(
new Tuple<Block, string, int>(
new Block(Block.Rows, Block.Positions, 0, i, d - 1), s2, CheckPosition));
1096 CheckPosition = Block.Positions[d] + 1;
1100 Segments?.AddLast(
new Tuple<Block, string, int>(
new Block(Block.Rows, Block.Positions, 0, i, c), s2, CheckPosition));
1102 LinkedList<MarkdownElement> Items;
1105 if (Segments is
null)
1107 List<Block> SubBlocks = Block.RemovePrefix(s2, 4);
1109 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 1)
1113 SubBlocks.Add(Block);
1116 Items = this.ParseBlocks(SubBlocks);
1126 Items =
new LinkedList<MarkdownElement>();
1129 foreach (Tuple<Block, string, int> Segment
in Segments)
1131 foreach (Block SegmentItem
in Segment.Item1.RemovePrefix(Segment.Item2, 4))
1133 LastItem =
new TaskItem(
this, Segment.Item2 !=
"[ ]", Segment.Item3,
1134 new NestedBlock(
this, this.ParseBlock(SegmentItem)));
1136 Items.AddLast(LastItem);
1146 if (!(LastItem is
null))
1149 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 0)
1157 Items = this.ParseBlocks(Blocks, i + 1, BlockIndex);
1161 if (LastItemChildren.IsBlockElement)
1162 LastItemChildren.AddChildren(Items);
1165 Items.AddFirst(
new Paragraph(
this, LastItemChildren.Children,
true));
1172 Items.AddFirst(LastItem.
Child);
1183 else if (Block.IsPrefixedByNumber(out Index))
1185 LinkedList<Tuple<int, bool, Block>> Segments =
null;
1188 bool Explicit =
true;
1190 for (d = Block.Start + 1; d <= c; d++)
1193 if (IsPrefixedByNumber(s, out j))
1195 if (Segments is
null)
1196 Segments =
new LinkedList<Tuple<int, bool, Block>>();
1198 Segments.AddLast(
new Tuple<int, bool, Block>(Index, Explicit,
new Block(Block.Rows, Block.Positions, 0, i, d - 1)));
1203 else if (IsPrefixedBy(s,
"#.",
true))
1205 if (Segments is
null)
1206 Segments =
new LinkedList<Tuple<int, bool, Block>>();
1208 Segments.AddLast(
new Tuple<int, bool, Block>(Index, Explicit,
new Block(Block.Rows, Block.Positions, 0, i, d - 1)));
1215 Segments?.AddLast(
new Tuple<int, bool, Block>(Index, Explicit,
new Block(Block.Rows, Block.Positions, 0, i, c)));
1217 LinkedList<MarkdownElement> Items;
1220 if (Segments is
null)
1223 List<Block> SubBlocks = Block.RemovePrefix(s +
".", Math.Max(4, s.Length + 2));
1225 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 1)
1229 SubBlocks.Add(Block);
1232 Items = this.ParseBlocks(SubBlocks);
1242 Items =
new LinkedList<MarkdownElement>();
1245 foreach (Tuple<int, bool, Block> Segment
in Segments)
1247 s = Segment.Item2 ? Segment.Item1.
ToString() +
"." :
"#.";
1248 foreach (Block SegmentItem
in Segment.Item3.RemovePrefix(s, Math.Max(4, s.Length + 2)))
1250 LastItem =
new NumberedItem(
this, Segment.Item1, Segment.Item2,
1251 new NestedBlock(
this, this.ParseBlock(SegmentItem)));
1253 Items.AddLast(LastItem);
1263 if (!(LastItem is
null))
1266 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 0)
1274 Items = this.ParseBlocks(Blocks, i + 1, BlockIndex);
1278 if (LastItemChildren.IsBlockElement)
1279 LastItemChildren.AddChildren(Items);
1282 Items.AddFirst(
new Paragraph(
this, LastItemChildren.Children,
true));
1289 Items.AddFirst(LastItem.
Child);
1300 else if (Block.IsTable(out TableInformation TableInformation))
1306 LinkedList<MarkdownElement> CellElements;
1310 c = TableInformation.Columns;
1312 for (j = 0; j < TableInformation.NrHeaderRows; j++)
1314 Row = TableInformation.Headers[j];
1315 Positions = TableInformation.HeaderPositions[j];
1320 for (i = 0; i < c; i++)
1326 HeaderCellAlignments[j][i] =
null;
1330 CellElements = this.ParseCell(Row[i], Positions[i], out HeaderCellAlignments[j][i]);
1332 if (!(CellElements.First is
null) && CellElements.First.Next is
null)
1336 FRef.AutoExpand =
true;
1338 if (this.footnotes.TryGetValue(FRef.Key, out
Footnote Note))
1339 Note.TableCellContents =
true;
1341 if (this.footnoteNumberByKey.TryGetValue(FRef.Key, out
int Nr) &&
1342 Nr ==
this.lastFootnote)
1344 this.footnoteNumberByKey.Remove(FRef.Key);
1345 this.lastFootnote--;
1349 Headers[j][i] = CellElements.First.Value;
1357 for (j = 0; j < TableInformation.NrDataRows; j++)
1359 Row = TableInformation.Rows[j];
1360 Positions = TableInformation.RowPositions[j];
1365 for (i = 0; i < c; i++)
1370 DataRows[j][i] =
null;
1371 DataCellAlignments[j][i] =
null;
1375 CellElements = this.ParseCell(Row[i], Positions[i], out DataCellAlignments[j][i]);
1377 if (!(CellElements.First is
null) && CellElements.First.Next is
null)
1381 FRef.AutoExpand =
true;
1383 if (this.footnotes.TryGetValue(FRef.Key, out
Footnote Note))
1384 Note.TableCellContents =
true;
1386 if (this.footnoteNumberByKey.TryGetValue(FRef.Key, out
int Nr) &&
1387 Nr ==
this.lastFootnote)
1389 this.footnoteNumberByKey.Remove(FRef.Key);
1390 this.lastFootnote--;
1394 DataRows[j][i] = CellElements.First.Value;
1397 DataRows[j][i] =
new NestedBlock(
this, CellElements);
1402 Elements.AddLast(
new Table(
this, c,
Headers, DataRows, TableInformation.Alignments, TableInformation.AlignmentDefinitions,
1403 HeaderCellAlignments, DataCellAlignments, TableInformation.Caption, TableInformation.
Id));
1407 else if (Block.IsPrefixedBy(
":",
true) && !(
Elements.Last is
null))
1409 LinkedList<MarkdownElement>
Description = this.ParseBlocks(Block.RemovePrefix(
":", 4));
1413 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 0)
1421 foreach (
MarkdownElement E
in this.ParseBlocks(Blocks, i + 1, BlockIndex))
1444 else if (BlockIndex < EndBlock && Blocks[BlockIndex + 1].IsPrefixedBy(
":",
true))
1446 LinkedList<MarkdownElement> Terms =
new LinkedList<MarkdownElement>();
1447 LinkedList<MarkdownElement> Term;
1451 for (i = Block.Start; i <= c; i++)
1453 Term = this.ParseBlock(Rows, Block.Positions, i, i);
1454 if (Term.First is
null)
1457 if (Term.First.Next is
null)
1458 Terms.AddLast(Term.First.Value);
1470 else if (Block.IsFootnote(out s, out
int WhiteSparePrefix))
1473 this.ParseBlocks(Block.RemovePrefix(
string.Empty, WhiteSparePrefix)));
1476 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 0)
1485 if (this.footnoteNumberByKey is
null)
1487 this.footnoteNumberByKey =
new Dictionary<string, int>();
1488 this.footnoteOrder =
new List<string>();
1489 this.footnotes =
new Dictionary<string, Footnote>();
1504 if (IsUnderline(s,
'=',
false,
false))
1506 Header Header =
new Header(
this, 1,
false, s, this.PrepareHeader(this.ParseBlock(Rows, Block.Positions, 0, c - 1)));
1508 this.headers.Add(
Header);
1511 else if (IsUnderline(s,
'-',
false,
false))
1513 Header Header =
new Header(
this, 2,
false, s, this.PrepareHeader(this.ParseBlock(Rows, Block.Positions, 0, c - 1)));
1515 this.headers.Add(
Header);
1520 s = Rows[Block.Start];
1521 if (IsPrefixedBy(s,
'#', out d,
true) && d < s.Length)
1523 string Prefix = s.Substring(0, d);
1524 Rows[Block.Start] = s.Substring(d).Trim();
1528 while (i >= 0 && s[i] ==
'#')
1532 Rows[c] = s.Substring(0, i).TrimEnd();
1534 Header Header =
new Header(
this, d,
true, Prefix, this.PrepareHeader(this.ParseBlock(Rows, Block.Positions, Block.Start, c)));
1536 this.headers.Add(
Header);
1540 Content = this.ParseBlock(Block, Blocks, ref BlockIndex, EndBlock);
1541 if (!(Content.First is
null))
1543 if (Content.First.Value is
InlineHTML && Content.Last.Value is
InlineHTML &&
this.settings.AllowHtml)
1545 else if (Content.First.Next is
null && Content.First.Value.OutsideParagraph)
1554 Elements.AddLast(Content.First.Value);
1563 LinkedList<MarkdownElement>
Sections =
new LinkedList<MarkdownElement>();
1571 private LinkedList<MarkdownElement> PrepareHeader(LinkedList<MarkdownElement> Content)
1574 Content.First.Next is
null &&
1579 LinkedList<MarkdownElement> NewContent =
new LinkedList<MarkdownElement>();
1580 NewContent.AddLast(
new InlineText(
this, Item.Number.ToString() +
". "));
1585 NewContent.AddLast(E);
1588 NewContent.AddLast(Item.Child);
1596 private LinkedList<MarkdownElement> ParseCell(
string Cell,
int Position, out
TextAlignment? Alignment)
1598 if (Cell.StartsWith(
"<<"))
1602 if (Cell.EndsWith(
">>"))
1605 Cell = Cell.Substring(2, Cell.Length - 4);
1610 Cell = Cell.Substring(2);
1613 else if (Cell.StartsWith(
">>") && Cell.EndsWith(
"<<"))
1616 Cell = Cell.Substring(2, Cell.Length - 4);
1619 else if (Cell.EndsWith(
">>"))
1622 Cell = Cell.Substring(0, Cell.Length - 2);
1627 return this.ParseBlock(
new string[] { Cell },
new int[] { Position });
1630 private LinkedList<MarkdownElement> ParseBlock(
string[] Rows,
int[] Positions)
1633 return this.ParseBlock(Rows, Positions, 0, Rows.Length - 1,
null, ref BlockIndex, 0);
1636 private LinkedList<MarkdownElement> ParseBlock(Block Block)
1639 return this.ParseBlock(Block.Rows, Block.Positions, Block.Start, Block.End,
null, ref BlockIndex, 0);
1642 private LinkedList<MarkdownElement> ParseBlock(Block Block, List<Block> Blocks, ref
int BlockIndex,
int EndBlock)
1644 return this.ParseBlock(Block.Rows, Block.Positions, Block.Start, Block.End, Blocks, ref BlockIndex, EndBlock);
1647 private LinkedList<MarkdownElement> ParseBlock(
string[] Rows,
int[] Positions,
int StartRow,
int EndRow)
1650 return this.ParseBlock(Rows, Positions, StartRow, EndRow,
null, ref BlockIndex, 0);
1653 private LinkedList<MarkdownElement> ParseBlock(
string[] Rows,
int[] Positions,
int StartRow,
int EndRow, List<Block> Blocks,
1654 ref
int BlockIndex,
int EndBlock)
1656 LinkedList<MarkdownElement>
Elements =
new LinkedList<MarkdownElement>();
1657 bool PreserveCrLf = Rows[StartRow].StartsWith(
"<") && Rows[EndRow].EndsWith(
">");
1658 BlockParseState State =
new BlockParseState(Rows, Positions, StartRow, EndRow, PreserveCrLf, Blocks, BlockIndex, EndBlock);
1660 this.ParseBlock(State, (
char)0, 1,
Elements,
true);
1662 BlockIndex = State.BlockIndex;
1666 private bool ParseBlock(BlockParseState State,
char TerminationCharacter,
int TerminationCharacterCount,
1667 LinkedList<MarkdownElement>
Elements,
bool AcceptIncomplete)
1669 LinkedList<MarkdownElement> ChildElements;
1670 StringBuilder Text =
new StringBuilder();
1673 char PrevChar =
' ';
1676 bool FirstCharOnLine;
1678 while ((ch = State.NextChar()) != (
char)0)
1680 if (ch == TerminationCharacter)
1682 if (TerminationCharacterCount == 1 ||
1683 State.CheckRestOfTermination(TerminationCharacter, TerminationCharacterCount - 1))
1692 this.AppendAnyText(
Elements, Text);
1701 if (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
1703 if (State.IsFirstCharOnLine)
1705 this.AppendAnyText(
Elements, Text);
1707 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
1708 State.NextCharSameRow();
1711 List<string> Rows =
new List<string>();
1712 List<int> Positions =
new List<int>()
1714 State.CurrentPosition
1717 Rows.Add(State.RestOfRow());
1721 if ((ch2 = State.PeekNextCharSameRow()) ==
'*' || ch2 ==
'+' || ch2 ==
'-')
1723 Item =
new UnnumberedItem(
this,
new string(ch, 1),
new NestedBlock(
this, this.ParseBlock(Rows.ToArray(), Positions.ToArray())));
1730 State.NextCharSameRow();
1731 State.SkipWhitespaceSameRow(3);
1736 Positions.Add(State.CurrentPosition);
1737 Rows.Add(State.RestOfRow());
1741 State.SkipWhitespaceSameRow(4);
1743 Positions.Add(State.CurrentPosition);
1744 Rows.Add(State.RestOfRow());
1750 Item =
new UnnumberedItem(
this,
new string(ch, 1),
new NestedBlock(
this, this.ParseBlock(Rows.ToArray(), Positions.ToArray())));
1764 this.AppendAnyText(
Elements, Text);
1765 ChildElements =
new LinkedList<MarkdownElement>();
1766 ch2 = State.PeekNextCharSameRow();
1769 State.NextCharSameRow();
1771 this.ParseBlock(State,
'*', 2, ChildElements,
true);
1776 if (this.emojiSource is
null)
1782 State.NextCharSameRow();
1787 State.BackupState();
1788 State.NextCharSameRow();
1790 if (State.PeekNextCharSameRow() ==
')')
1792 State.DiscardBackup();
1793 State.NextCharSameRow();
1798 State.RestoreState();
1800 if (this.ParseBlock(State,
'*', 1, ChildElements, TerminationCharacter !=
'*'))
1803 this.FixSyntaxError(
Elements,
"*", ChildElements);
1808 State.BackupState();
1809 State.NextCharSameRow();
1810 if ((ch3 = State.NextCharSameRow()) ==
'0' || ch3 ==
'O')
1812 if (State.NextCharSameRow() ==
'/')
1814 if (State.NextCharSameRow() ==
'*')
1816 State.DiscardBackup();
1817 this.AppendAnyText(
Elements, Text);
1824 State.RestoreState();
1825 if (this.ParseBlock(State,
'*', 1, ChildElements, TerminationCharacter !=
'*'))
1828 this.FixSyntaxError(
Elements,
"*", ChildElements);
1833 if (this.ParseBlock(State,
'*', 1, ChildElements, TerminationCharacter !=
'*'))
1836 this.FixSyntaxError(
Elements,
"*", ChildElements);
1843 if ((ch2 = State.PeekNextCharSameRow()) <=
' ' || ch2 == 160)
1849 this.AppendAnyText(
Elements, Text);
1850 ChildElements =
new LinkedList<MarkdownElement>();
1851 ch2 = State.PeekNextCharSameRow();
1854 State.NextCharSameRow();
1856 this.ParseBlock(State,
'_', 2, ChildElements,
true);
1861 if (this.ParseBlock(State,
'_', 1, ChildElements, TerminationCharacter !=
'_'))
1864 this.FixSyntaxError(
Elements,
"_", ChildElements);
1869 if ((ch2 = State.PeekNextCharSameRow()) <=
' ' || ch2 == 160)
1875 this.AppendAnyText(
Elements, Text);
1876 ChildElements =
new LinkedList<MarkdownElement>();
1877 ch2 = State.PeekNextCharSameRow();
1880 State.NextCharSameRow();
1882 this.ParseBlock(State,
'~', 2, ChildElements,
true);
1887 if (this.ParseBlock(State,
'~', 1, ChildElements, TerminationCharacter !=
'~'))
1890 this.FixSyntaxError(
Elements,
"~", ChildElements);
1895 this.AppendAnyText(
Elements, Text);
1896 ch2 = State.PeekNextCharSameRow();
1899 State.NextCharSameRow();
1901 while ((ch2 = State.NextChar()) != 0)
1903 if (ch2 ==
'`' && State.PeekNextCharSameRow() ==
'`')
1905 State.NextCharSameRow();
1914 while ((ch2 = State.NextChar()) !=
'`' && ch2 != 0)
1924 FirstCharOnLine = State.IsFirstCharOnLine;
1928 ch2 = State.PeekNextCharSameRow();
1935 State.NextCharSameRow();
1939 ch2 = State.PeekNextCharSameRow();
1942 State.NextCharSameRow();
1943 this.AppendAnyText(
Elements, Text);
1947 else if (ch2 ==
'%')
1949 State.NextCharSameRow();
1950 this.AppendAnyText(
Elements, Text);
1952 while ((ch3 = State.NextCharSameRow()) !=
']' && ch3 != 0)
1957 Url = Text.ToString();
1958 if (
string.
Compare(Url,
"Details",
true) == 0)
1965 Text.Insert(0,
"[%");
1969 else if (ch2 ==
'^')
1971 State.NextCharSameRow();
1972 this.AppendAnyText(
Elements, Text);
1974 while ((ch3 = State.NextChar()) !=
']' && ch3 != 0)
1979 Url = Text.ToString();
1982 if (this.footnoteNumberByKey is
null)
1984 this.footnoteNumberByKey =
new Dictionary<string, int>();
1985 this.footnoteOrder =
new List<string>();
1986 this.footnotes =
new Dictionary<string, Footnote>();
1991 Title = Url.ToLower();
1993 if (!this.footnoteNumberByKey.ContainsKey(
Title))
1995 this.footnoteNumberByKey[
Title] = ++this.lastFootnote;
1996 this.footnoteOrder.Add(
Title);
2001 Title = Guid.NewGuid().ToString();
2004 this.footnoteNumberByKey[
Title] = ++this.lastFootnote;
2005 this.footnoteOrder.Add(
Title);
2006 this.footnotes[
Title] =
new Footnote(
this,
Title,
new Paragraph(
this, this.ParseBlock(
new string[] { Url },
new int[] { State.CurrentPosition - 1 - Url.Length })));
2010 Text.Insert(0,
"[^");
2018 if (FirstCharOnLine && (((chs = State.PeekNextChars(3))[0] ==
' ' || chs[0] ==
'x' || chs[0] ==
'X') && chs[1] ==
']' && ((chs[2] <=
' ' && chs[2] > 0) || chs[2] == 160)))
2020 int CheckPosition = State.CurrentPosition;
2026 this.AppendAnyText(
Elements, Text);
2028 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
2029 State.NextCharSameRow();
2032 List<string> Rows =
new List<string>()
2036 List<int> Positions =
new List<int>()
2038 State.CurrentPosition
2040 bool Checked = (chs[0] !=
' ');
2044 if ((chs = State.PeekNextChars(4))[0] ==
'[' &&
2045 (chs[1] ==
' ' || chs[1] ==
'x' || chs[1] ==
'X') &&
2046 chs[2] ==
']' && ((chs[3] <=
' ' && chs[3] > 0) || chs[3] == 160))
2048 Item =
new TaskItem(
this, Checked, CheckPosition,
2049 new NestedBlock(
this, this.ParseBlock(Rows.ToArray(), Positions.ToArray())));
2061 CheckPosition = State.CurrentPosition;
2067 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
2068 State.NextCharSameRow();
2070 Positions.Add(State.CurrentPosition);
2071 Rows.Add(State.RestOfRow());
2073 Checked = (chs[1] !=
' ');
2077 State.SkipWhitespaceSameRow(4);
2078 Positions.Add(State.CurrentPosition);
2079 Rows.Add(State.RestOfRow());
2085 Item =
new TaskItem(
this, Checked, CheckPosition,
2086 new NestedBlock(
this, this.ParseBlock(Rows.ToArray(), Positions.ToArray())));
2097 ChildElements =
new LinkedList<MarkdownElement>();
2098 this.AppendAnyText(
Elements, Text);
2100 if (this.ParseBlock(State,
']', 1, ChildElements,
false))
2102 ch2 = State.PeekNextNonWhitespaceChar(
false);
2105 State.NextNonWhitespaceChar();
2106 Title =
string.Empty;
2108 while ((ch2 = State.PeekNextCharSameRow()) != 0 && ch2 >
' ' && ch2 !=
')' && ch2 != 160)
2114 Url = Text.ToString();
2115 if (Url.StartsWith(
"abbr:", StringComparison.CurrentCultureIgnoreCase))
2121 while ((ch2 = State.NextCharSameRow()) != 0 && ch2 !=
')')
2125 Url = Text.ToString();
2134 if (Url.StartsWith(
"<") && Url.EndsWith(
">"))
2135 Url = Url.Substring(1, Url.Length - 2);
2137 if (ch2 <=
' ' || ch2 == 160)
2139 ch2 = State.PeekNextNonWhitespaceChar(
true);
2141 if (ch2 ==
'"' || ch2 ==
'\'')
2143 State.NextNonWhitespaceChar();
2144 while ((ch3 = State.NextCharSameRow()) != 0 && ch3 != ch2)
2147 Title = Text.ToString();
2150 ch2 = State.PeekNextNonWhitespaceChar(
true);
2153 Title =
string.Empty;
2156 if (ch ==
'!' && ch2 !=
')')
2158 ParseWidthHeight(State, out Width, out Height);
2159 ch2 = State.PeekNextCharSameRow();
2162 Width = Height =
null;
2164 while (ch2 != 0 && ch2 !=
')')
2166 State.NextCharSameRow();
2167 ch2 = State.PeekNextCharSameRow();
2175 List<MultimediaItem> Items =
new List<MultimediaItem>()
2180 if (!this.includesTableOfContents &&
string.
Compare(Url,
"ToC",
true) == 0)
2181 this.includesTableOfContents =
true;
2183 State.BackupState();
2184 ch2 = State.PeekNextNonWhitespaceChar(
false);
2188 State.NextNonWhitespaceChar();
2189 Title =
string.Empty;
2191 while ((ch2 = State.PeekNextCharSameRow()) != 0 && ch2 >
' ' && ch2 !=
')' && ch2 != 160)
2197 Url = Text.ToString();
2201 if (Url.StartsWith(
"<") && Url.EndsWith(
">"))
2202 Url = Url.Substring(1, Url.Length - 2);
2204 if (ch2 <=
' ' || ch2 == 160)
2206 ch2 = State.PeekNextNonWhitespaceChar(
true);
2208 if (ch2 ==
'"' || ch2 ==
'\'')
2210 State.NextNonWhitespaceChar();
2211 while ((ch3 = State.NextCharSameRow()) != 0 && ch3 != ch2)
2214 Title = Text.ToString();
2217 ch2 = State.PeekNextNonWhitespaceChar(
true);
2220 Title =
string.Empty;
2225 ParseWidthHeight(State, out Width, out Height);
2227 ch2 = State.PeekNextCharSameRow();
2229 while (ch2 != 0 && ch2 !=
')')
2231 State.NextCharSameRow();
2232 ch2 = State.PeekNextCharSameRow();
2241 ch2 = State.PeekNextNonWhitespaceChar(
true);
2244 State.DiscardBackup();
2245 State.BackupState();
2248 State.RestoreState();
2257 else if (ch2 ==
':' && FirstCharOnLine)
2259 State.NextNonWhitespaceChar();
2260 ch2 = State.NextChar();
2261 while ((ch2 != 0 && ch2 <=
' ') || ch2 == 160)
2262 ch2 = State.NextChar();
2264 if (ch2 >
' ' && ch2 != 160)
2266 List<MultimediaItem> Items =
new List<MultimediaItem>();
2270 while (ch2 >
' ' && ch2 != 160 && ch2 !=
'[')
2272 ch2 = State.NextNonWhitespaceChar();
2273 while (ch2 != 0 && ch2 >
' ' && ch2 != 160)
2276 ch2 = State.NextCharSameRow();
2279 Url = Text.ToString();
2282 if (Url.StartsWith(
"<") && Url.EndsWith(
">"))
2283 Url = Url.Substring(1, Url.Length - 2);
2285 ch2 = State.PeekNextNonWhitespaceChar(
true);
2287 if (ch2 ==
'"' || ch2 ==
'\'' || ch2 ==
'(')
2289 State.NextNonWhitespaceChar();
2293 while ((ch3 = State.NextCharSameRow()) != 0 && ch3 != ch2)
2296 Title = Text.ToString();
2300 Title =
string.Empty;
2302 ParseWidthHeight(State, out Width, out Height);
2305 if (!this.includesTableOfContents &&
string.
Compare(Url,
"ToC",
true) == 0)
2306 this.includesTableOfContents =
true;
2308 ch2 = State.PeekNextNonWhitespaceChar(
true);
2317 this.references[Text.ToString().ToLower()] =
new Multimedia(
this,
null,
2318 Elements.First is
null && State.PeekNextChar() == 0, Items.ToArray());
2323 else if (ch2 ==
'[')
2325 State.NextNonWhitespaceChar();
2326 while ((ch2 = State.NextCharSameRow()) != 0 && ch2 !=
']')
2329 Title = Text.ToString();
2332 if (
string.IsNullOrEmpty(
Title))
2340 Title = Text.ToString();
2347 Elements.First is
null && State.PeekNextChar() == 0));
2356 this.FixSyntaxError(
Elements,
"![", ChildElements);
2365 this.FixSyntaxError(
Elements, ch ==
'!' ?
"![" :
"[", ChildElements);
2369 ch2 = State.PeekNextCharSameRow();
2372 State.NextCharSameRow();
2373 this.AppendAnyText(
Elements, Text);
2381 ch2 = State.PeekNextCharSameRow();
2384 State.NextCharSameRow();
2385 this.AppendAnyText(
Elements, Text);
2387 ch3 = State.PeekNextCharSameRow();
2390 State.NextCharSameRow();
2397 else if (ch2 ==
'-')
2399 State.NextCharSameRow();
2400 ch3 = State.PeekNextCharSameRow();
2404 State.NextCharSameRow();
2405 this.AppendAnyText(
Elements, Text);
2407 ch3 = State.PeekNextCharSameRow();
2410 State.NextCharSameRow();
2420 else if (ch2 ==
'=')
2422 State.NextCharSameRow();
2423 this.AppendAnyText(
Elements, Text);
2424 ch3 = State.PeekNextCharSameRow();
2428 State.NextCharSameRow();
2430 ch3 = State.PeekNextCharSameRow();
2433 State.NextCharSameRow();
2443 else if (ch2 ==
'>')
2445 State.NextCharSameRow();
2446 this.AppendAnyText(
Elements, Text);
2450 else if (ch2 ==
'3' && !(this.emojiSource is
null))
2452 State.NextCharSameRow();
2453 this.AppendAnyText(
Elements, Text);
2457 else if (ch2 ==
'/')
2459 State.NextCharSameRow();
2460 if (!(this.emojiSource is
null) && State.PeekNextCharSameRow() ==
'3')
2462 State.NextCharSameRow();
2463 this.AppendAnyText(
Elements, Text);
2469 if ((!
char.IsLetter(ch2) && ch2 !=
'/') || !this.settings.AllowHtml)
2475 this.AppendAnyText(
Elements, Text);
2481 while ((ch2 = State.NextChar()) != 0 && ch2 !=
'>')
2493 Url = Text.ToString();
2495 if (Url.StartsWith(
"</"))
2497 if (Url.StartsWith(
"</script", StringComparison.CurrentCultureIgnoreCase))
2502 else if (Url.StartsWith(
"<script", StringComparison.CurrentCultureIgnoreCase))
2506 Text.Append(State.UntilToken(
"</SCRIPT>"));
2508 Text.Append(Url.Substring(1, 6));
2516 else if (Url.StartsWith(
"<textarea", StringComparison.CurrentCultureIgnoreCase))
2520 string s = State.UntilToken(
"</TEXTAREA>");
2522 if (!
string.IsNullOrEmpty(s))
2529 int i = Url.IndexOf(
' ');
2531 if ((i < 0 && Url.IndexOf(
':') >= 0) || (i > 0 && Url.LastIndexOf(
':', i) >= 0))
2533 else if ((i < 0 && Url.IndexOf(
'@') >= 0) || (i > 0 && Url.LastIndexOf(
'@', i) >= 0))
2539 if (Url.StartsWith(
"<textarea", StringComparison.CurrentCultureIgnoreCase))
2541 string s = State.UntilToken(
"</TEXTAREA>");
2543 if (!
string.IsNullOrEmpty(s))
2555 switch (State.PeekNextCharSameRow())
2558 State.NextCharSameRow();
2559 this.AppendAnyText(
Elements, Text);
2561 ch3 = State.PeekNextCharSameRow();
2564 State.NextCharSameRow();
2572 this.AppendAnyText(
Elements, Text);
2573 State.NextCharSameRow();
2575 if (!(this.emojiSource is
null) && State.PeekNextCharSameRow() ==
')')
2577 State.NextCharSameRow();
2585 if (!(this.emojiSource is
null))
2587 State.NextCharSameRow();
2588 switch (State.PeekNextCharSameRow())
2591 State.NextCharSameRow();
2592 this.AppendAnyText(
Elements, Text);
2597 State.NextCharSameRow();
2598 this.AppendAnyText(
Elements, Text);
2603 State.NextCharSameRow();
2604 this.AppendAnyText(
Elements, Text);
2609 State.NextCharSameRow();
2610 this.AppendAnyText(
Elements, Text);
2619 State.NextCharSameRow();
2620 this.AppendAnyText(
Elements, Text);
2627 State.NextCharSameRow();
2628 this.AppendAnyText(
Elements, Text);
2635 State.NextCharSameRow();
2636 this.AppendAnyText(
Elements, Text);
2641 State.NextCharSameRow();
2642 switch (State.PeekNextCharSameRow())
2645 State.NextCharSameRow();
2646 this.AppendAnyText(
Elements, Text);
2651 State.NextCharSameRow();
2652 this.AppendAnyText(
Elements, Text);
2672 if (!(this.emojiSource is
null))
2674 State.NextCharSameRow();
2675 if (State.PeekNextCharSameRow() ==
')')
2677 State.NextCharSameRow();
2678 this.AppendAnyText(
Elements, Text);
2689 if (!(this.emojiSource is
null))
2691 State.NextCharSameRow();
2692 if (State.PeekNextCharSameRow() ==
'<')
2694 State.NextCharSameRow();
2695 this.AppendAnyText(
Elements, Text);
2712 if (!this.settings.AllowInlineScript ||
this.settings.Variables is
null)
2714 int Pos = State.CurrentPosition - 1;
2715 if (Pos < this.markdownText.Length &&
this.markdownText[Pos] ==
'{')
2717 if (this.toInsert is
null)
2718 this.toInsert =
new SortedDictionary<int, string>(
new ReversePosition());
2720 this.toInsert[Pos] =
"\\";
2721 if (Pos > 0 && ((ch2 = this.markdownText[Pos - 1]) ==
':' || ch2 ==
'*' || ch2 ==
'='))
2722 this.toInsert[Pos - 1] =
"\\";
2728 this.AppendAnyText(
Elements, Text);
2729 State.BackupState();
2731 int StartPosition = State.CurrentPosition - 1;
2733 while ((ch2 = State.NextChar()) !=
'}' && ch2 != 0)
2736 int EndPosition = State.CurrentPosition;
2740 State.RestoreState();
2748 State.DiscardBackup();
2751 Elements.First is
null && State.PeekNextChar() == 0, StartPosition, EndPosition));
2753 this.isDynamic =
true;
2755 catch (Exception ex)
2761 new InlineHTML(
this,
"<font class=\"error\">")
2764 if (ex is AggregateException ex2)
2766 foreach (Exception ex3
in ex2.InnerExceptions)
2768 this.CheckException(ex3);
2780 this.CheckException(ex);
2795 this.CheckException(ex);
2801 ch2 = State.PeekNextCharSameRow();
2804 State.NextCharSameRow();
2805 this.AppendAnyText(
Elements, Text);
2807 ch3 = State.PeekNextCharSameRow();
2811 State.NextCharSameRow();
2814 else if (ch3 ==
'-')
2816 State.NextCharSameRow();
2822 else if (ch2 ==
'+')
2824 State.NextCharSameRow();
2825 this.AppendAnyText(
Elements, Text);
2828 else if (ch2 ==
'_')
2830 if (!(this.emojiSource is
null))
2832 State.BackupState();
2833 while ((ch2 = State.NextCharSameRow()) ==
'_')
2838 State.DiscardBackup();
2839 State.NextCharSameRow();
2840 this.AppendAnyText(
Elements, Text);
2845 State.RestoreState();
2852 else if ((ch2 <= ' ' && ch2 > 0) || ch2 == 160)
2854 if (State.IsFirstCharOnLine)
2856 this.AppendAnyText(
Elements, Text);
2858 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
2859 State.NextCharSameRow();
2862 List<string> Rows =
new List<string>();
2863 List<int> Positions =
new List<int>()
2865 State.CurrentPosition
2868 Rows.Add(State.RestOfRow());
2872 if ((ch2 = State.PeekNextCharSameRow()) ==
'*' || ch2 ==
'+' || ch2 ==
'-')
2874 Item =
new UnnumberedItem(
this,
new string(ch, 1),
new NestedBlock(
this, this.ParseBlock(Rows.ToArray(), Positions.ToArray())));
2881 State.NextCharSameRow();
2882 State.SkipWhitespaceSameRow(3);
2887 Positions.Add(State.CurrentPosition);
2888 Rows.Add(State.RestOfRow());
2892 State.SkipWhitespaceSameRow(4);
2894 Positions.Add(State.CurrentPosition);
2895 Rows.Add(State.RestOfRow());
2901 Item =
new UnnumberedItem(
this,
new string(ch, 1),
new NestedBlock(
this, this.ParseBlock(Rows.ToArray(), Positions.ToArray())));
2917 ch2 = State.PeekNextCharSameRow();
2920 State.NextCharSameRow();
2921 this.AppendAnyText(
Elements, Text);
2924 else if ((ch2 <= ' ' && ch2 > 0) || ch2 == 160)
2926 if (State.IsFirstCharOnLine)
2928 this.AppendAnyText(
Elements, Text);
2930 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
2931 State.NextCharSameRow();
2934 List<string> Rows =
new List<string>();
2935 List<int> Positions =
new List<int>()
2937 State.CurrentPosition
2940 Rows.Add(State.RestOfRow());
2944 if ((ch2 = State.PeekNextCharSameRow()) ==
'*' || ch2 ==
'+' || ch2 ==
'-')
2946 Item =
new UnnumberedItem(
this,
new string(ch, 1),
new NestedBlock(
this, this.ParseBlock(Rows.ToArray(), Positions.ToArray())));
2953 State.NextCharSameRow();
2954 State.SkipWhitespaceSameRow(3);
2959 Positions.Add(State.CurrentPosition);
2960 Rows.Add(State.RestOfRow());
2964 State.SkipWhitespaceSameRow(4);
2966 Positions.Add(State.CurrentPosition);
2967 Rows.Add(State.RestOfRow());
2973 Item =
new UnnumberedItem(
this,
new string(ch, 1),
new NestedBlock(
this, this.ParseBlock(Rows.ToArray(), Positions.ToArray())));
2989 ch2 = State.PeekNextCharSameRow();
2990 if (
char.IsLetterOrDigit(ch2))
2992 this.AppendAnyText(
Elements, Text);
2995 State.NextCharSameRow();
2997 while (
char.IsLetterOrDigit(ch2 = State.PeekNextCharSameRow()))
3000 State.NextCharSameRow();
3006 else if (State.IsFirstCharOnLine && ch2 ==
'.')
3008 State.NextCharSameRow();
3010 if (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
3012 this.AppendAnyText(
Elements, Text);
3014 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
3015 State.NextCharSameRow();
3018 List<string> Rows =
new List<string>();
3019 List<int> Positions =
new List<int>()
3021 State.CurrentPosition
3024 Rows.Add(State.RestOfRow());
3028 if (State.PeekNextCharSameRow() ==
'#')
3030 State.NextCharSameRow();
3031 if (State.PeekNextCharSameRow() ==
'.')
3033 Item =
new NumberedItem(
this, 1,
false,
new NestedBlock(
this, this.ParseBlock(Rows.ToArray(), Positions.ToArray())));
3040 State.NextCharSameRow();
3041 State.SkipWhitespaceSameRow(3);
3046 Positions.Add(State.CurrentPosition);
3047 Rows.Add(State.RestOfRow());
3051 State.SkipWhitespaceSameRow(4);
3053 Positions.Add(State.CurrentPosition - 1);
3054 Rows.Add(
"#" + State.RestOfRow());
3059 State.SkipWhitespaceSameRow(4);
3061 Positions.Add(State.CurrentPosition);
3062 Rows.Add(State.RestOfRow());
3068 Item =
new NumberedItem(
this, 1,
false,
new NestedBlock(
this, this.ParseBlock(Rows.ToArray(), Positions.ToArray())));
3075 Item.Number = PrevItem.Number + 1;
3084 else if (!(this.emojiSource is
null))
3086 switch (State.PeekNextCharSameRow())
3089 State.BackupState();
3090 State.NextCharSameRow();
3091 switch (State.PeekNextCharSameRow())
3094 State.DiscardBackup();
3095 State.NextCharSameRow();
3096 this.AppendAnyText(
Elements, Text);
3101 State.RestoreState();
3108 State.NextCharSameRow();
3109 this.AppendAnyText(
Elements, Text);
3132 if (!(this.emojiSource is
null) && (ch ==
'8' || ch ==
'0') && (
char.IsPunctuation(PrevChar) ||
char.IsWhiteSpace(PrevChar)))
3136 switch (ch2 = State.PeekNextCharSameRow())
3139 State.BackupState();
3140 State.NextCharSameRow();
3141 switch (State.PeekNextCharSameRow())
3145 State.DiscardBackup();
3146 State.NextCharSameRow();
3147 this.AppendAnyText(
Elements, Text);
3153 State.NextCharSameRow();
3154 switch (State.PeekNextCharSameRow())
3158 State.DiscardBackup();
3159 State.NextCharSameRow();
3160 this.AppendAnyText(
Elements, Text);
3166 State.RestoreState();
3172 State.RestoreState();
3178 State.BackupState();
3179 State.NextCharSameRow();
3180 switch (State.PeekNextCharSameRow())
3184 State.NextCharSameRow();
3185 switch (State.PeekNextCharSameRow())
3188 State.DiscardBackup();
3189 State.NextCharSameRow();
3190 this.AppendAnyText(
Elements, Text);
3196 State.RestoreState();
3202 State.RestoreState();
3213 switch (ch2 = State.PeekNextCharSameRow())
3216 State.BackupState();
3217 State.NextCharSameRow();
3218 switch (State.PeekNextCharSameRow())
3222 State.DiscardBackup();
3223 State.NextCharSameRow();
3224 this.AppendAnyText(
Elements, Text);
3230 State.RestoreState();
3236 State.NextCharSameRow();
3237 this.AppendAnyText(
Elements, Text);
3247 if (ch2 == (
char)0xffff)
3251 if (State.IsFirstCharOnLine)
3253 StringBuilder sb =
new StringBuilder();
3256 while ((ch2 = State.PeekNextCharSameRow()) >=
'0' && ch2 <=
'9')
3258 State.NextCharSameRow();
3264 State.NextCharSameRow();
3265 if ((((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160) &&
3266 int.TryParse(sb.ToString(), out
int Index))
3268 this.AppendAnyText(
Elements, Text);
3270 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
3271 State.NextCharSameRow();
3274 List<string> Rows =
new List<string>();
3275 List<int> Positions =
new List<int>()
3277 State.CurrentPosition
3280 Rows.Add(State.RestOfRow());
3284 if ((ch2 = State.PeekNextCharSameRow()) >=
'0' && ch2 <=
'9')
3287 while ((ch2 = State.NextCharSameRow()) >=
'0' && ch2 <=
'9')
3290 if (ch2 ==
'.' &&
int.TryParse(sb.ToString(), out
int Index2))
3292 Item =
new NumberedItem(
this, Index,
true,
new NestedBlock(
this, this.ParseBlock(Rows.ToArray(), Positions.ToArray())));
3299 State.NextCharSameRow();
3300 State.SkipWhitespaceSameRow(3);
3305 Positions.Add(State.CurrentPosition);
3306 Rows.Add(State.RestOfRow());
3311 State.SkipWhitespaceSameRow(4);
3313 string s = sb.ToString();
3314 Positions.Add(State.CurrentPosition - 1 - s.Length);
3315 Rows.Add(s + ch2 + State.RestOfRow());
3320 State.SkipWhitespaceSameRow(4);
3322 Positions.Add(State.CurrentPosition);
3323 Rows.Add(State.RestOfRow());
3329 Item =
new NumberedItem(
this, Index,
true,
new NestedBlock(
this, this.ParseBlock(Rows.ToArray(), Positions.ToArray())));
3339 Text.Append(sb.ToString());
3344 Text.Append(sb.ToString());
3351 ch2 = State.PeekNextCharSameRow();
3352 if (this.emojiSource is
null && ch2 !=
'=')
3358 State.NextCharSameRow();
3359 this.AppendAnyText(
Elements, Text);
3361 ch3 = State.PeekNextCharSameRow();
3364 State.NextCharSameRow();
3372 State.NextCharSameRow();
3373 this.AppendAnyText(
Elements, Text);
3379 State.NextCharSameRow();
3380 this.AppendAnyText(
Elements, Text);
3385 State.NextCharSameRow();
3386 this.AppendAnyText(
Elements, Text);
3392 State.NextCharSameRow();
3393 this.AppendAnyText(
Elements, Text);
3398 State.NextCharSameRow();
3399 this.AppendAnyText(
Elements, Text);
3406 State.NextCharSameRow();
3407 this.AppendAnyText(
Elements, Text);
3416 State.NextCharSameRow();
3417 this.AppendAnyText(
Elements, Text);
3424 State.NextCharSameRow();
3425 this.AppendAnyText(
Elements, Text);
3436 if (
char.IsLetter(ch2 = State.PeekNextCharSameRow()))
3438 this.AppendAnyText(
Elements, Text);
3441 while (
char.IsLetter(ch2 = State.NextCharSameRow()))
3450 Url = Text.ToString();
3455 else if (ch2 ==
'#')
3459 this.AppendAnyText(
Elements, Text);
3460 State.NextCharSameRow();
3464 if ((ch3 = State.PeekNextCharSameRow()) ==
'x' || ch3 ==
'X')
3467 State.NextCharSameRow();
3469 while (((ch3 =
char.ToUpper(State.PeekNextCharSameRow())) >=
'0' && ch3 <=
'9') || (ch3 >=
'A' && ch3 <=
'F'))
3471 State.NextCharSameRow();
3475 if (ch3 ==
';' &&
int.TryParse(Text.ToString().Substring(3), System.Globalization.NumberStyles.HexNumber,
null, out Code))
3477 State.NextCharSameRow();
3483 else if (
char.IsDigit(ch3))
3485 while (
char.IsDigit(ch3 = State.PeekNextCharSameRow()))
3487 State.NextCharSameRow();
3491 if (ch3 ==
';' &&
int.TryParse(Text.ToString().Substring(2), out Code))
3493 State.NextCharSameRow();
3506 this.AppendAnyText(
Elements, Text);
3507 if (IsLeftQuote(PrevChar, State.PeekNextCharSameRow()))
3514 this.AppendAnyText(
Elements, Text);
3516 if (!(this.emojiSource is
null))
3517 ch2 = State.PeekNextCharSameRow();
3524 State.NextCharSameRow();
3525 switch (State.PeekNextCharSameRow())
3529 State.NextCharSameRow();
3534 State.NextCharSameRow();
3539 State.NextCharSameRow();
3540 switch (State.PeekNextCharSameRow())
3544 State.NextCharSameRow();
3549 State.NextCharSameRow();
3554 if (IsLeftQuote(PrevChar, State.PeekNextCharSameRow()))
3565 if (IsLeftQuote(PrevChar, State.PeekNextCharSameRow()))
3576 State.NextCharSameRow();
3577 switch (State.PeekNextCharSameRow())
3581 State.NextCharSameRow();
3586 State.NextCharSameRow();
3591 if (IsLeftQuote(PrevChar, State.PeekNextCharSameRow()))
3602 if (IsLeftQuote(PrevChar, State.PeekNextCharSameRow()))
3611 if (State.PeekNextCharSameRow() ==
'.')
3613 State.NextCharSameRow();
3614 if (State.PeekNextCharSameRow() ==
'.')
3616 State.NextCharSameRow();
3617 this.AppendAnyText(
Elements, Text);
3629 ch2 = State.PeekNextCharSameRow();
3630 ch3 =
char.ToLower(ch2);
3631 if (ch3 ==
'c' || ch3 ==
'r' || ch3 ==
'p' || ch3 ==
's')
3633 State.NextCharSameRow();
3634 if (State.PeekNextCharSameRow() ==
')')
3636 State.NextCharSameRow();
3638 this.AppendAnyText(
Elements, Text);
3691 switch (State.PeekNextCharSameRow())
3694 State.NextCharSameRow();
3695 this.AppendAnyText(
Elements, Text);
3697 ch3 = State.PeekNextCharSameRow();
3700 State.NextCharSameRow();
3708 if (!(this.emojiSource is
null))
3710 State.BackupState();
3711 State.NextCharSameRow();
3712 switch (State.PeekNextCharSameRow())
3715 State.DiscardBackup();
3716 State.NextCharSameRow();
3717 this.AppendAnyText(
Elements, Text);
3722 State.RestoreState();
3732 if (!(this.emojiSource is
null))
3734 State.NextCharSameRow();
3735 this.AppendAnyText(
Elements, Text);
3749 ch2 = State.PeekNextCharSameRow();
3753 State.NextCharSameRow();
3754 this.AppendAnyText(
Elements, Text);
3759 State.NextCharSameRow();
3760 this.AppendAnyText(
Elements, Text);
3765 State.NextCharSameRow();
3766 this.AppendAnyText(
Elements, Text);
3771 State.NextCharSameRow();
3772 this.AppendAnyText(
Elements, Text);
3777 State.NextCharSameRow();
3778 this.AppendAnyText(
Elements, Text);
3783 State.NextCharSameRow();
3784 this.AppendAnyText(
Elements, Text);
3839 State.NextCharSameRow();
3840 this.AppendAnyText(
Elements, Text);
3845 State.NextCharSameRow();
3846 this.AppendAnyText(
Elements, Text);
3848 if (State.PeekNextCharSameRow() ==
'M')
3850 State.NextCharSameRow();
3858 State.NextCharSameRow();
3859 this.AppendAnyText(
Elements, Text);
3861 if (State.PeekNextCharSameRow() ==
't')
3863 State.NextCharSameRow();
3871 State.NextCharSameRow();
3872 this.AppendAnyText(
Elements, Text);
3874 if (State.PeekNextCharSameRow() ==
'd')
3876 State.NextCharSameRow();
3884 State.NextCharSameRow();
3885 this.AppendAnyText(
Elements, Text);
3887 if (State.PeekNextCharSameRow() ==
'd')
3889 State.NextCharSameRow();
3897 State.NextCharSameRow();
3898 this.AppendAnyText(
Elements, Text);
3900 if (State.PeekNextCharSameRow() ==
'h')
3902 State.NextCharSameRow();
3910 State.NextCharSameRow();
3911 this.AppendAnyText(
Elements, Text);
3913 ChildElements =
new LinkedList<MarkdownElement>();
3915 this.ParseBlock(State,
')', 1, ChildElements,
true);
3920 State.NextCharSameRow();
3921 this.AppendAnyText(
Elements, Text);
3923 ChildElements =
new LinkedList<MarkdownElement>();
3925 this.ParseBlock(State,
']', 1, ChildElements,
true);
3936 if ((ch2 = State.PeekNextCharSameRow()) <=
' ' || ch2 == 160)
3938 if (State.IsFirstCharOnLine && ch2 > 0)
3940 LinkedList<MarkdownElement> TotItem =
null;
3941 LinkedList<MarkdownElement> Item;
3945 for (i = State.Start; i < State.Current; i++)
3947 Item = this.ParseBlock(State.Rows, State.Positions, i, i);
3948 if (Item.First is
null)
3951 if (TotItem is
null)
3953 if (Item.First.Next is
null)
3956 TotItem.AddLast(Item.First.Value);
3960 if (TotItem is
null)
3961 TotItem =
new LinkedList<MarkdownElement>();
3967 if (TotItem is
null)
3977 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
3978 State.NextCharSameRow();
3980 List<string> Rows =
new List<string>();
3981 List<int> Positions =
new List<int>()
3983 State.CurrentPosition
3986 Rows.Add(State.RestOfRow());
3990 if (State.PeekNextCharSameRow() ==
':')
3994 State.NextCharSameRow();
3995 State.SkipWhitespaceSameRow(3);
4000 Positions.Add(State.CurrentPosition);
4001 Rows.Add(State.RestOfRow());
4005 State.SkipWhitespaceSameRow(4);
4007 Positions.Add(State.CurrentPosition);
4008 Rows.Add(State.RestOfRow());
4019 else if (!(this.emojiSource is
null))
4025 State.NextCharSameRow();
4026 ch2 = State.PeekNextCharSameRow();
4029 if (
char.IsLetter(ch2) ||
char.IsDigit(ch2) || ch2 ==
'+')
4031 this.AppendAnyText(
Elements, Text);
4032 State.NextCharSameRow();
4034 ch3 = State.PeekNextCharSameRow();
4035 if (
char.IsLetter(ch3) ||
char.IsDigit(ch3) || ch3 ==
'_' || ch3 ==
'-' || ch3 ==
':')
4042 State.NextCharSameRow();
4044 Text.Append(
new string(
':', LeftLevel - 1));
4046 this.AppendAnyText(
Elements, Text);
4051 State.NextCharSameRow();
4053 Text.Append(
new string(
':', LeftLevel - 1));
4055 this.AppendAnyText(
Elements, Text);
4064 State.NextCharSameRow();
4066 Text.Append(
new string(
':', LeftLevel - 1));
4068 this.AppendAnyText(
Elements, Text);
4074 State.NextCharSameRow();
4076 Text.Append(
new string(
':', LeftLevel - 1));
4078 this.AppendAnyText(
Elements, Text);
4084 State.NextCharSameRow();
4086 Text.Append(
new string(
':', LeftLevel - 1));
4088 this.AppendAnyText(
Elements, Text);
4102 while (
char.IsLetter(ch3 = State.PeekNextCharSameRow()) ||
char.IsDigit(ch3) || ch3 ==
'_' || ch3 ==
'-')
4104 State.NextCharSameRow();
4112 while (ch3 ==
':' && RightLevel < LeftLevel)
4115 State.NextCharSameRow();
4116 ch3 = State.PeekNextCharSameRow();
4119 Title = Text.ToString().ToLower();
4123 if (LeftLevel > RightLevel)
4131 Text.Insert(0,
new string(
':', LeftLevel));
4132 Text.Append(
new string(
':', RightLevel));
4136 Text.Insert(0,
new string(
':', LeftLevel));
4141 Text.Append(
new string(
':', LeftLevel - 1));
4146 State.NextCharSameRow();
4148 switch (State.PeekNextCharSameRow())
4151 State.NextCharSameRow();
4152 this.AppendAnyText(
Elements, Text);
4157 State.NextCharSameRow();
4158 this.AppendAnyText(
Elements, Text);
4163 State.NextCharSameRow();
4164 if ((ch3 = State.PeekNextCharSameRow()) ==
')')
4166 State.NextCharSameRow();
4167 this.AppendAnyText(
Elements, Text);
4170 else if (ch3 ==
'(')
4172 State.NextCharSameRow();
4173 this.AppendAnyText(
Elements, Text);
4187 State.NextCharSameRow();
4189 switch (State.PeekNextCharSameRow())
4193 State.NextCharSameRow();
4194 this.AppendAnyText(
Elements, Text);
4200 State.NextCharSameRow();
4201 this.AppendAnyText(
Elements, Text);
4206 State.NextCharSameRow();
4207 this.AppendAnyText(
Elements, Text);
4212 State.NextCharSameRow();
4213 this.AppendAnyText(
Elements, Text);
4221 State.NextCharSameRow();
4222 this.AppendAnyText(
Elements, Text);
4231 State.NextCharSameRow();
4232 this.AppendAnyText(
Elements, Text);
4238 State.NextCharSameRow();
4239 this.AppendAnyText(
Elements, Text);
4246 State.NextCharSameRow();
4247 this.AppendAnyText(
Elements, Text);
4252 State.NextCharSameRow();
4253 if ((ch3 = State.PeekNextCharSameRow()) ==
')')
4255 State.NextCharSameRow();
4256 this.AppendAnyText(
Elements, Text);
4259 else if (ch3 ==
'(')
4261 State.NextCharSameRow();
4262 this.AppendAnyText(
Elements, Text);
4270 State.NextCharSameRow();
4271 if (State.PeekNextCharSameRow() ==
':')
4273 State.NextCharSameRow();
4274 this.AppendAnyText(
Elements, Text);
4289 State.NextCharSameRow();
4290 this.AppendAnyText(
Elements, Text);
4296 State.NextCharSameRow();
4297 this.AppendAnyText(
Elements, Text);
4302 State.NextCharSameRow();
4303 this.AppendAnyText(
Elements, Text);
4309 State.NextCharSameRow();
4310 this.AppendAnyText(
Elements, Text);
4315 State.NextCharSameRow();
4316 this.AppendAnyText(
Elements, Text);
4321 State.NextCharSameRow();
4322 this.AppendAnyText(
Elements, Text);
4327 State.NextCharSameRow();
4328 this.AppendAnyText(
Elements, Text);
4333 State.NextCharSameRow();
4334 if (State.PeekNextCharSameRow() ==
'*')
4336 State.NextCharSameRow();
4337 this.AppendAnyText(
Elements, Text);
4355 if (!(this.emojiSource is
null))
4357 switch (State.PeekNextCharSameRow())
4362 State.NextCharSameRow();
4363 this.AppendAnyText(
Elements, Text);
4369 State.NextCharSameRow();
4370 this.AppendAnyText(
Elements, Text);
4375 State.NextCharSameRow();
4376 switch (State.PeekNextCharSameRow())
4380 State.NextCharSameRow();
4381 this.AppendAnyText(
Elements, Text);
4387 State.NextCharSameRow();
4388 this.AppendAnyText(
Elements, Text);
4399 State.NextCharSameRow();
4400 if (State.PeekNextCharSameRow() ==
')')
4402 State.NextCharSameRow();
4403 this.AppendAnyText(
Elements, Text);
4421 if (!(this.emojiSource is
null) && (
char.IsPunctuation(PrevChar) ||
char.IsWhiteSpace(PrevChar)))
4423 switch (State.PeekNextCharSameRow())
4426 State.BackupState();
4427 State.NextCharSameRow();
4428 switch (State.PeekNextCharSameRow())
4435 State.DiscardBackup();
4436 State.NextCharSameRow();
4437 this.AppendAnyText(
Elements, Text);
4442 State.DiscardBackup();
4443 State.NextCharSameRow();
4444 this.AppendAnyText(
Elements, Text);
4449 State.RestoreState();
4456 State.NextCharSameRow();
4457 this.AppendAnyText(
Elements, Text);
4471 if (!(this.emojiSource is
null) && (
char.IsPunctuation(PrevChar) ||
char.IsWhiteSpace(PrevChar)))
4473 switch (State.PeekNextCharSameRow())
4476 State.BackupState();
4477 State.NextCharSameRow();
4478 switch (State.PeekNextCharSameRow())
4482 State.DiscardBackup();
4483 State.NextCharSameRow();
4484 this.AppendAnyText(
Elements, Text);
4489 State.RestoreState();
4496 State.NextCharSameRow();
4497 this.AppendAnyText(
Elements, Text);
4511 if (!(this.emojiSource is
null) && (
char.IsPunctuation(PrevChar) ||
char.IsWhiteSpace(PrevChar)) && State.PeekNextCharSameRow() ==
':')
4513 State.NextCharSameRow();
4514 this.AppendAnyText(
Elements, Text);
4522 if (!(this.emojiSource is
null) && (
char.IsPunctuation(PrevChar) ||
char.IsWhiteSpace(PrevChar)))
4524 switch (State.PeekNextCharSameRow())
4527 State.BackupState();
4528 State.NextCharSameRow();
4529 switch (State.NextCharSameRow())
4533 State.DiscardBackup();
4534 this.AppendAnyText(
Elements, Text);
4539 if ((ch3 = State.NextCharSameRow()) ==
')' || ch3 ==
'3')
4541 State.DiscardBackup();
4542 this.AppendAnyText(
Elements, Text);
4547 State.RestoreState();
4553 State.RestoreState();
4560 State.BackupState();
4561 State.NextCharSameRow();
4562 if (State.NextCharSameRow() ==
'-')
4564 if (State.NextCharSameRow() ==
')')
4566 State.DiscardBackup();
4567 this.AppendAnyText(
Elements, Text);
4573 State.RestoreState();
4578 State.BackupState();
4579 State.NextCharSameRow();
4580 if (State.PeekNextCharSameRow() ==
')')
4582 State.NextCharSameRow();
4583 State.DiscardBackup();
4584 this.AppendAnyText(
Elements, Text);
4589 State.RestoreState();
4595 State.BackupState();
4596 State.NextCharSameRow();
4597 if (State.PeekNextCharSameRow() ==
'O')
4599 State.NextCharSameRow();
4600 State.DiscardBackup();
4601 this.AppendAnyText(
Elements, Text);
4606 State.RestoreState();
4621 if (
char.IsWhiteSpace(PrevChar) && State.PeekNextCharSameRow() ==
't')
4623 FirstCharOnLine = State.IsFirstCharOnLine;
4625 chs = State.PeekNextChars(7);
4626 if (chs[1] ==
't' && chs[2] ==
'p' &&
4627 ((chs[3] ==
':' && chs[4] ==
'/' && chs[5] ==
'/') ||
4628 (chs[3] ==
's' && chs[4] ==
':' && chs[5] ==
'/' && chs[6] ==
'/')))
4630 this.AppendAnyText(
Elements, Text);
4642 Text.Append(State.NextChar());
4646 while ((ch2 = State.PeekNextCharSameRow()) >
' ' && ch2 != 160)
4652 Url = Text.ToString();
4655 if (FirstCharOnLine && State.PeekNextNonWhitespaceCharSameRow(
false) == 0)
4660 ChildElements =
new LinkedList<MarkdownElement>();
4661 ChildElements.AddLast(
new InlineText(
this, Url));
4680 switch (ch2 = State.PeekNextCharSameRow())
4710 State.NextCharSameRow();
4715 if (!(this.emojiSource is
null))
4717 State.BackupState();
4718 State.NextCharSameRow();
4719 if (State.PeekNextCharSameRow() ==
'/')
4721 State.DiscardBackup();
4722 State.NextCharSameRow();
4723 this.AppendAnyText(
Elements, Text);
4728 State.RestoreState();
4747 PrevChar = State.LastCharacter;
4750 this.AppendAnyText(
Elements, Text);
4752 return (ch == TerminationCharacter) || AcceptIncomplete;
4755 private static bool IsLeftQuote(
char PrevChar,
char NextChar)
4757 bool Left = (PrevChar <=
' ' || PrevChar == 160 ||
char.IsPunctuation(PrevChar) ||
char.IsSeparator(PrevChar));
4758 bool Right = (NextChar <=
' ' || NextChar == 160 ||
char.IsPunctuation(NextChar) ||
char.IsSeparator(NextChar));
4762 if (
char.IsSeparator(PrevChar))
4764 else if (
char.IsSeparator(NextChar))
4766 else if (PrevChar ==
')' || PrevChar ==
']' || PrevChar ==
'}')
4768 else if (NextChar ==
'(' || NextChar ==
'[' || NextChar ==
'[')
4777 private static void ParseWidthHeight(BlockParseState State, out
int? Width, out
int? Height)
4782 char ch = State.PeekNextNonWhitespaceCharSameRow(
true);
4783 if (ch >=
'0' && ch <=
'9')
4785 StringBuilder Text =
new StringBuilder();
4788 State.NextNonWhitespaceCharSameRow();
4790 ch = State.PeekNextCharSameRow();
4791 while (ch >=
'0' && ch <=
'9')
4794 State.NextCharSameRow();
4795 ch = State.PeekNextCharSameRow();
4798 if (
int.TryParse(Text.ToString(), out
int i))
4803 ch = State.PeekNextNonWhitespaceCharSameRow(
true);
4804 if (ch >=
'0' && ch <=
'9')
4807 State.NextNonWhitespaceCharSameRow();
4809 ch = State.PeekNextCharSameRow();
4810 while (ch >=
'0' && ch <=
'9')
4813 State.NextCharSameRow();
4814 ch = State.PeekNextCharSameRow();
4817 if (
int.TryParse(Text.ToString(), out i))
4824 private void AppendAnyText(LinkedList<MarkdownElement>
Elements, StringBuilder Text)
4826 if (Text.Length > 0)
4828 string s = Text.ToString();
4831 if (!(
Elements.First is
null) || !
string.IsNullOrEmpty(s.Trim()))
4836 private void FixSyntaxError(LinkedList<MarkdownElement>
Elements,
string Prefix, LinkedList<MarkdownElement> ChildElements)
4843 internal static bool IsPrefixedByNumber(
string s, out
int Numeral)
4845 int i, c = s.Length;
4849 while (i < c &&
char.IsDigit(s[i]))
4858 if (!
int.TryParse(s.Substring(0, i), out Numeral) || i == c || s[i] !=
'.')
4862 if (i < c && (ch = s[i]) >
' ' && ch != 160)
4868 internal static bool IsPrefixedBy(
string s,
string Prefix,
bool MustHaveWhiteSpaceAfter)
4873 if (!s.StartsWith(Prefix))
4876 if (MustHaveWhiteSpaceAfter)
4878 if (s.Length == (i =
Prefix.Length))
4881 return (ch = s[i]) <=
' ' || ch == 160;
4887 private static bool IsPrefixedBy(
string s,
char ch, out
int Count,
bool MustHaveWhiteSpaceAfter)
4892 while (Count < c && s[Count] == ch)
4898 if (MustHaveWhiteSpaceAfter)
4900 if (s.Length == Count)
4903 return (ch = s[Count]) <=
' ' || ch == 160;
4909 internal static bool IsSuffixedBy(
string s,
string Suffix)
4911 return s.EndsWith(Suffix);
4928 private static bool IsUnderline(
string s,
char ch,
bool AllowSpaces,
bool OnlyOneSpace)
4930 int i, c = s.Length;
4931 bool LastSpace =
true;
4935 for (i = 0; i < c; i++)
4943 else if (ch2 ==
' ' || ch2 == 160)
4945 if (OnlyOneSpace && (!AllowSpaces || LastSpace))
4957 private static List<Block> ParseTextToBlocks(
string MarkdownText)
4959 List<Block> Blocks =
new List<Block>();
4960 List<string> Rows =
new List<string>();
4961 List<int> Positions =
new List<int>();
4962 int FirstLineIndent = 0;
4968 bool InBlock =
false;
4970 bool NonWhitespaceInRow =
false;
4971 bool StartsWithHashSigns =
false;
4972 bool IsHeader =
false;
4973 bool HasRows =
false;
4977 for (Pos = 0; Pos < Len; Pos++)
4985 if (InRow && NonWhitespaceInRow)
4988 LineIndent < FirstLineIndent &&
4991 Blocks.Add(
new Block(Rows.ToArray(), Positions.ToArray(), FirstLineIndent / 4));
4994 FirstLineIndent = LineIndent;
4997 Positions.Add(RowStart);
4998 Rows.Add(
MarkdownText.Substring(RowStart, RowEnd - RowStart + 1));
5002 if (IsHeader && Rows.Count == 1)
5004 Blocks.Add(
new Block(Rows.ToArray(), Positions.ToArray(), FirstLineIndent / 4));
5009 FirstLineIndent = 0;
5014 Blocks.Add(
new Block(Rows.ToArray(), Positions.ToArray(), FirstLineIndent / 4));
5020 FirstLineIndent = 0;
5024 FirstLineIndent = 0;
5027 NonWhitespaceInRow =
false;
5028 StartsWithHashSigns =
false;
5031 else if (ch <=
' ' || ch == 160)
5039 if (StartsWithHashSigns)
5044 if (LineIndent >= FirstLineIndent)
5047 RowStart = RowEnd = Pos;
5052 else if (ch ==
' ' || ch == 160)
5056 else if (ch ==
'\t')
5057 FirstLineIndent += 4;
5058 else if (ch ==
' ' || ch == 160)
5061 StartsWithHashSigns =
false;
5072 StartsWithHashSigns =
true;
5075 StartsWithHashSigns =
false;
5078 NonWhitespaceInRow =
true;
5084 if (InRow && NonWhitespaceInRow)
5086 Positions.Add(RowStart);
5087 Rows.Add(
MarkdownText.Substring(RowStart, RowEnd - RowStart + 1));
5091 Blocks.Add(
new Block(Rows.ToArray(), Positions.ToArray(), FirstLineIndent / 4));
5097 private static bool IsListPrefix(
string MarkdownText,
int Pos)
5103 if (ch ==
'*' || ch ==
'+' || ch ==
'-')
5104 ExpectPeriod =
false;
5106 ExpectPeriod =
true;
5109 ExpectPeriod =
false;
5114 if (ch !=
' ' && ch !=
'x' && ch !=
'X')
5124 else if (ch >=
'0' && ch <=
'9')
5126 ExpectPeriod =
true;
5128 while (Pos < c && (ch =
MarkdownText[Pos]) >=
'0' && ch <=
'9')
5149 return ch <=
' ' || ch == 160;
5158 if (this.metaData.TryGetValue(
"MASTER", out KeyValuePair<string, bool>[]
Master) &&
Master.Length == 1)
5160 await this.LoadMasterIfNotLoaded(
Master[0].Key);
5161 this.master.ClearFootnoteReferences();
5166 this.ClearFootnoteReferences();
5176 private void ClearFootnoteReferences()
5178 if (!(this.footnotes is
null))
5181 Footnote.Referenced =
false;
5190 private async Task LoadMasterIfNotLoaded(
string MasterMetaValue)
5192 if (this.master is
null)
5196 if (!
string.IsNullOrEmpty(this.fileName))
5197 FileName = this.settings.GetFileName(this.fileName, MasterMetaValue);
5198 else if (!
string.IsNullOrEmpty(this.resourceName))
5200 FileName = Path.Combine(this.resourceName, MasterMetaValue);
5201 if (!(this.settings.ResourceMap is
null) &&
this.settings.ResourceMap.TryGetFileName(
FileName,
false, out
string s))
5210 this.master.syntaxHighlighting |= this.syntaxHighlighting;
5212 if (this.master.metaData.ContainsKey(
"MASTER"))
5214 throw new GenericException(
"Master documents are not allowed to be embedded in other master documents.",
5218 CopyMetaDataTags(
this, this.master,
true);
5220 this.master.detail =
this;
5226 if (UpdateMasterPaths && !
string.IsNullOrEmpty(Details.fileName) && !
string.IsNullOrEmpty(
Master.fileName))
5228 string DetailsFileName = Path.GetFullPath(Details.fileName);
5229 string MasterFileName = Path.GetFullPath(
Master.fileName);
5230 string DetailsFolder = Path.GetDirectoryName(DetailsFileName);
5231 string MasterFolder = Path.GetDirectoryName(MasterFileName);
5233 if (DetailsFolder != MasterFolder)
5235 string Prefix =
null;
5237 foreach (KeyValuePair<
string, KeyValuePair<string, bool>[]> Meta
in Master.metaData)
5255 int i, j, k, l, c, d;
5257 for (k = 0, l = Meta.Value.Length; k < l; k++)
5259 string s = Meta.Value[k].Key;
5260 if (
string.IsNullOrEmpty(s))
5263 if (s[0] == Path.DirectorySeparatorChar || s[0] ==
'/')
5268 string[] DetailsParts = DetailsFolder.Split(Path.DirectorySeparatorChar);
5269 string[] MasterParts = MasterFolder.Split(Path.DirectorySeparatorChar);
5272 c = DetailsParts.Length;
5273 d = MasterParts.Length;
5275 while (i < c && i < d &&
string.
Compare(DetailsParts[i], MasterParts[i],
true) == 0)
5278 StringBuilder sb =
new StringBuilder();
5287 sb.Append(MasterParts[i++]);
5291 Prefix = sb.ToString();
5294 Meta.Value[k] =
new KeyValuePair<string, bool>(Prefix + s, Meta.Value[k].Value);
5302 foreach (KeyValuePair<
string, KeyValuePair<string, bool>[]> Meta
in Details.metaData)
5304 if (
Master.metaData.TryGetValue(Meta.Key, out KeyValuePair<string, bool>[] Meta0))
5305 Master.metaData[Meta.Key] = Concat(Meta0, Meta.Value);
5307 Master.metaData[Meta.Key] = Meta.Value;
5311 private static KeyValuePair<string, bool>[] Concat(KeyValuePair<string, bool>[] Meta1, KeyValuePair<string, bool>[] Meta2)
5313 int c = Meta1.Length;
5314 int d = Meta2.Length;
5315 KeyValuePair<string, bool>[] Result =
new KeyValuePair<string, bool>[c + d];
5317 Array.Copy(Meta1, 0, Result, 0, c);
5318 Array.Copy(Meta2, 0, Result, c, d);
5326 internal bool NeedsToDisplayFootnotes
5330 if (this.footnotes is
null)
5352 bool IsRelative = Url.IndexOf(
':') < 0;
5354 if (Url.StartsWith(
"httpx:", StringComparison.OrdinalIgnoreCase) && !
string.IsNullOrEmpty(
this.settings.HttpxProxy))
5356 if (!
string.IsNullOrEmpty(this.settings.LocalHttpxResourcePath) &&
5357 Url.StartsWith(
this.settings.LocalHttpxResourcePath, StringComparison.OrdinalIgnoreCase))
5359 Url = Url.Substring(this.settings.LocalHttpxResourcePath.Length);
5360 if (!Url.StartsWith(
"/") &&
this.settings.LocalHttpxResourcePath.EndsWith(
"/"))
5367 Url = this.settings.HttpxProxy.Replace(
"%URL%", Url);
5368 IsRelative = this.settings.HttpxProxy.IndexOf(
':') < 0;
5372 if (IsRelative && !
string.IsNullOrEmpty(
URL))
5374 if (Uri.TryCreate(
new Uri(
URL), Url, out Uri AbsoluteUri))
5375 Url = AbsoluteUri.ToString();
5398 StringBuilder Output =
new StringBuilder();
5400 return Output.ToString();
5422 PortableSyntax = PortableSyntax
5435 StringBuilder Output =
new StringBuilder();
5437 return Output.ToString();
5456 StringBuilder Output =
new StringBuilder();
5458 return Output.ToString();
5480 StringBuilder Output =
new StringBuilder();
5482 return Output.ToString();
5504 if (this.references.TryGetValue(Label.ToLower(), out
Multimedia Result))
5510 private static readonly
char[] whiteSpace =
new char[]
5512 (char)1, (
char)2, (char)3, (
char)4, (char)5, (
char)6, (char)7, (
char)8, (char)9,(
char)10,
5513 (char)11, (
char)12, (char)13, (
char)14, (char)15, (
char)16, (char)17, (
char)18, (char)19,(
char)20,
5514 (char)21, (
char)22, (char)23, (
char)24, (char)25, (
char)26, (char)27, (
char)28, (char)29,(
char)30,
5531 return this.metaData.TryGetValue(Key.ToUpper(), out Value);
5541 if (this.metaData.TryGetValue(Key, out KeyValuePair<string, bool>[] Records))
5543 List<KeyValuePair<string, bool>> Values =
new List<KeyValuePair<string, bool>>();
5544 Values.AddRange(Records);
5545 Values.Add(
new KeyValuePair<string, bool>(Value.Trim(), Value.EndsWith(
" ")));
5548 this.metaData[Key] =
new KeyValuePair<string, bool>[] {
new KeyValuePair<string, bool>(Value.Trim(), Value.EndsWith(
" ")) };
5558 if (!this.metaData.TryGetValue(Key.ToUpper(), out KeyValuePair<string, bool>[] Value))
5559 return new string[0];
5561 int i, c = Value.Length;
5562 string[] Result =
new string[c];
5564 for (i = 0; i < c; i++)
5565 Result[i] = Value[i].Key;
5577 string[] Keys =
new string[this.metaData.Count];
5578 this.metaData.Keys.CopyTo(Keys, 0);
5586 public IEnumerable<KeyValuePair<string, KeyValuePair<string, bool>[]>>
MetaData => this.metaData;
5591 public IEnumerable<KeyValuePair<string, Multimedia>>
References => this.references;
5608 private string[] Merge(
string[] L1,
string[] L2)
5612 if ((c1 = L1.Length) == 0)
5614 else if ((c2 = L2.Length) == 0)
5617 string[] L =
new string[c1 + c2];
5619 Array.Copy(L1, 0, L, 0, c1);
5620 Array.Copy(L2, 0, L, c1, c2);
5720 if (this.footnoteNumberByKey is
null)
5726 return this.footnoteNumberByKey.TryGetValue(Key, out Number);
5737 if (this.footnotes is
null)
5743 return this.footnotes.TryGetValue(Key, out
Footnote);
5754 if (this.footnoteOrder is
null)
5755 return new string[0];
5757 return this.footnoteOrder.ToArray();
5773 return Functions.MarkdownEncode.EscapeText(s);
5786 get => this.fileName;
5787 set => this.fileName = value;
5796 get => this.resourceName;
5797 set => this.resourceName = value;
5806 set => this.url = value;
5815 set => this.master = value;
5825 if (!(this.detail is
null))
5828 if (this.master is
null)
5837 set => this.detail = value;
5853 public bool IsDynamic => this.isDynamic || (this.master?.isDynamic ??
false);
5861 set => this.tag = value;
5871 if (!this.allowScriptTag.HasValue)
5873 this.allowScriptTag = this.metaData.TryGetValue(
"ALLOWSCRIPTTAG", out KeyValuePair<string, bool>[] Value) &&
5879 return this.allowScriptTag.Value;
5891 if (!(this.elements is
null))
5895 if (!E.
ForEach(Callback, State))
5900 if (!(this.references is
null))
5904 if (!E.
ForEach(Callback, State))
5909 if (!(this.footnotes is
null))
5913 if (!E.
ForEach(Callback, State))
5927 return this.
FindLinks(
true,
true,
true);
5937 public string[]
FindLinks(
bool IncludeAutomaticLinks,
bool IncludeLinks,
bool IncludeMultimedia)
5939 Dictionary<string, bool> Links =
new Dictionary<string, bool>();
5945 if (IncludeAutomaticLinks)
5955 if (IncludeMultimedia)
5958 Links[Item.
Url] =
true;
5965 string[] Result =
new string[Links.Count];
5966 Links.Keys.CopyTo(Result, 0);
5976 SortedDictionary<string, bool> Tags =
new SortedDictionary<string, bool>();
5981 Tags[
Tag.Tag] =
true;
5986 string[] Result =
new string[Tags.Count];
5987 Tags.Keys.CopyTo(Result, 0);
5994 public IEnumerable<MarkdownElement>
Elements => this.elements;
6001 return this.elements.GetEnumerator();
6004 IEnumerator IEnumerable.GetEnumerator()
6006 return this.elements.GetEnumerator();
6009 private class ReversePosition : IComparer<int>
6011 public int Compare(
int x,
int y)
6026 return New.
Compare(Old, KeepUnchanged);
6060 IEnumerable<MarkdownElement> Edit =
Compare(
Previous.elements,
this.elements, KeepUnchanged, Result);
6063 Result.elements.AddLast(E);
6067 Result.markdownText =
null;
6071 private static IEnumerable<MarkdownElement> Atomize(IEnumerable<MarkdownElement>
Elements, out
bool Reassemble)
6073 if (ContainsEditableText(
Elements))
6085 private static IEnumerable<MarkdownElement> Atomize(IEnumerable<MarkdownElement>
Elements)
6087 LinkedList<MarkdownElement> Result =
new LinkedList<MarkdownElement>();
6103 private static bool ContainsEditableText(IEnumerable<MarkdownElement>
Elements)
6119 if (
Elements is ICollection<MarkdownElement> Collection)
6122 Collection.CopyTo(Array, 0);
6141 private static IEnumerable<MarkdownElement>
Compare(IEnumerable<MarkdownElement> Elements1,
6142 IEnumerable<MarkdownElement> Elements2,
bool KeepUnchanged,
MarkdownDocument Document)
6144 LinkedList<MarkdownElement> Result =
new LinkedList<MarkdownElement>();
6145 MarkdownElement[] S1 = ToArray(Atomize(Elements1, out
bool Reassemble1));
6146 MarkdownElement[] S2 = ToArray(Atomize(Elements2, out
bool Reassemble2));
6149 int i, c =
Script.Steps.Length;
6151 if (Reassemble1 || Reassemble2)
6153 List<MarkdownElement> Reassembled =
new List<MarkdownElement>();
6154 StringBuilder sb =
new StringBuilder();
6156 for (i = 0; i < c; i++)
6177 Type LastAtomType =
null;
6178 Atom LastAtom =
null;
6185 AtomType =
Atom.GetType();
6186 if (AtomType != LastAtomType)
6188 if (!(LastAtom is
null))
6190 Reassembled.Add(LastAtom.
Source.
Assemble(Document, sb.ToString()));
6195 LastAtomType = AtomType;
6202 if (!(LastAtom is
null))
6204 Reassembled.Add(LastAtom.
Source.
Assemble(Document, sb.ToString()));
6207 LastAtomType =
null;
6214 if (!(LastAtom is
null))
6216 Reassembled.Add(LastAtom.
Source.
Assemble(Document, sb.ToString()));
6220 Step.Symbols = Reassembled.ToArray();
6221 Reassembled.Clear();
6225 for (i = 0; i < c; i++)
6247 for (j = 0; j < d; j++)
6252 E1 = Step2.Symbols[j];
6257 E2 = Step2.Symbols[j];
6263 IEnumerable<MarkdownElement> Diff =
Compare(Children1.Children, Children2.Children,
6264 KeepUnchanged || d > 1, Document);
6266 Result.AddLast(Children1.Create(Diff, Document));
6274 IEnumerable<MarkdownElement> Diff =
Compare(GrandChildren1.Children, GrandChildren2.Children,
6275 KeepUnchanged || d > 1, Document);
6277 Result.AddLast(Child1.Create(GrandChildren1.Create(Diff, Document), Document));
6282 Result.AddLast(GetElement(Step2.Operation, Document, E2));
6298 if (Symbols[0].IsBlockElement)
6314 return new Insert(Document, Symbols);
6317 return new Delete(Document, Symbols);
6326 int i, c = E1.Length;
6332 for (i = 0; i < c; i++)
6334 if (!(e = E1[i]).IsBlockElement)
6352 lock (this.asyncTasks)
6354 this.asyncTasks.Add(
new KeyValuePair<AsyncMarkdownProcessing, object>(Callback, State));
6361 public IEnumerable<KeyValuePair<AsyncMarkdownProcessing, object>>
AsyncTasks
6365 lock (this.asyncTasks)
6367 return this.asyncTasks.ToArray();
6377 KeyValuePair<AsyncMarkdownProcessing, object>[] Tasks;
6379 lock (this.asyncTasks)
6381 if (this.asyncTasks.Count == 0)
6384 Tasks = this.asyncTasks.ToArray();
6385 this.asyncTasks.Clear();
6388 Task.Run(async () =>
6390 foreach (KeyValuePair<AsyncMarkdownProcessing, object> P
in Tasks)
6394 await P.Key(P.Value);
6396 catch (Exception ex)
6415 if (Visualizer is
null)
6420 catch (Exception ex)
6437 Element.IncrementStatistics(Result);
6441 Result.MailHyperlinks = Result.IntMailHyperlinks?.ToArray();
6442 Result.UrlHyperlinks = Result.IntUrlHyperlinks?.ToArray();
6444 this.GenerateStatDictionary(Result.IntMultimediaPerContentCategory,
6445 out Dictionary<
string,
string[]> AsArrays, out Dictionary<string, int> AsCounts);
6447 Result.MultimediaPerContentCategory = AsArrays;
6448 Result.NrMultimediaPerContentCategory = AsCounts;
6450 this.GenerateStatDictionary(Result.IntMultimediaPerContentType, out AsArrays, out AsCounts);
6451 Result.MultimediaPerContentType = AsArrays;
6452 Result.NrMultimediaPerContentType = AsCounts;
6454 this.GenerateStatDictionary(Result.IntMultimediaPerExtension, out AsArrays, out AsCounts);
6455 Result.MultimediaPerExtension = AsArrays;
6456 Result.NrMultimediaPerExtension = AsCounts;
6461 private void GenerateStatDictionary(Dictionary<
string, List<string>> Temp, out Dictionary<
string,
string[]> AsArrays, out Dictionary<string, int> AsCounts)
6470 AsArrays =
new Dictionary<string, string[]>();
6471 AsCounts =
new Dictionary<string, int>();
6473 foreach (KeyValuePair<
string, List<string>> P
in Temp)
6475 AsArrays[P.Key] = P.Value.ToArray();
6476 AsCounts[P.Key] = P.Value.Count;
6498 if (SingleRow && Rows.Length == 1)
6499 return Rows[0].Trim();
6501 StringBuilder sb =
new StringBuilder();
6503 foreach (
string Row
in Rows)
6506 sb.Append(Row.Trim());
6511 return sb.ToString();
Helps with parsing of commong data types.
static readonly char[] CRLF
Contains the CR LF character sequence.
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Contains information about an emoji.
Static class that provide methods for managing emojis.
static readonly EmojiInfo Emoji_sweat
:sweat: 😓 face with cold sweat
static readonly EmojiInfo Emoji_joy
:joy: 😂 face with tears of joy
static readonly EmojiInfo Emoji_no_mouth
:no_mouth: 😶 face without mouth
static readonly EmojiInfo Emoji_broken_heart
:broken_heart: 💔 broken heart
static readonly EmojiInfo Emoji_kissing_heart
:kissing_heart: 😘 face throwing a kiss
static readonly EmojiInfo Emoji_wink
:wink: 😉 winking face
static readonly EmojiInfo Emoji_stuck_out_tongue_winking_eye
:stuck_out_tongue_winking_eye: 😜 face with stuck-out tongue and winking eye
static readonly EmojiInfo Emoji_heart
:heart: ❤ heavy black heart
static readonly EmojiInfo Emoji_cry
:cry: 😢 crying face
static bool TryGetEmoji(string ShortName, out EmojiInfo Emoji)
Tries to get information about an emoji, given its short name.
static readonly EmojiInfo Emoji_angry
:angry: 😠 angry face
static readonly EmojiInfo Emoji_expressionless
:expressionless: 😑 expressionless face
static readonly EmojiInfo Emoji_disappointed
:disappointed: 😞 disappointed face
static readonly EmojiInfo Emoji_ok_woman
:ok_woman: 🙆 face with ok gesture
static readonly EmojiInfo Emoji_sweat_smile
:sweat_smile: 😅 smiling face with open mouth and cold sweat
static readonly EmojiInfo Emoji_stuck_out_tongue
:stuck_out_tongue: 😛 face with stuck-out tongue
static readonly EmojiInfo Emoji_smile
:smile: 😄 smiling face with open mouth and smiling eyes
static readonly EmojiInfo Emoji_innocent
:innocent: 😇 smiling face with halo
static readonly EmojiInfo Emoji_persevere
:persevere: 😣 persevering face
static readonly EmojiInfo Emoji__1
:-1: 👎 thumbs down sign
static readonly EmojiInfo Emoji_flushed
:flushed: 😳 flushed face
static readonly EmojiInfo Emoji_open_mouth
:open_mouth: 😮 face with open mouth
static readonly EmojiInfo Emoji_smiley
:smiley: 😃 smiling face with open mouth
static readonly EmojiInfo Emoji_dizzy_face
:dizzy_face: 😵 dizzy face
static readonly EmojiInfo Emoji_sunglasses
:sunglasses: 😎 smiling face with sunglasses
static readonly EmojiInfo Emoji_laughing
:laughing: 😆 smiling face with open mouth and tightly-closed eyes
static readonly EmojiInfo Emoji_confused
:confused: 😕 confused face
Executes script from a file, if not executed before, or if file timestamp has changed....
static async Task< bool > NeedsExecution(string FileName)
Checks if an init-file needs to be executed.
Class that can be used to encapsulate Markdown to be returned from a Web Service, bypassing any encod...
Contains a markdown document. This markdown document class supports original markdown,...
string[] Script
Links to server-side script files that should be included before processing the page.
static async Task< object > TransformXml(XmlDocument Xml, Variables Variables)
Transforms XML to an object that is easier to visualize.
static string AppendRows(string[] Rows)
Appends a set of rows into a single string with newlines between rows.
string[] InitializationScript
Links to server-side script files that should be executed before before processing the page....
MarkdownSettings Settings
Markdown settings.
IEnumerable< KeyValuePair< AsyncMarkdownProcessing, object > > AsyncTasks
Enumerable set of asynchronous tasks that have been registered.
async Task< MarkdownDocument > Compare(MarkdownDocument Previous, bool KeepUnchanged)
Calculates the difference of the current Markdown document, and a previous version of the Markdown do...
bool IncludesTableOfContents
If the document contains a Table of Contents.
Task GenerateHTML(StringBuilder Output)
Generates HTML from the markdown text.
string CheckURL(string Url, string URL)
Checks the URL if it needs redirection to a proxy.
string[] FindLinks(bool IncludeAutomaticLinks, bool IncludeLinks, bool IncludeMultimedia)
Finds all links in the document.
bool ForEach(MarkdownElementHandler Callback, object State)
Loops through all elements in the document.
static string Encode(string s)
Encodes all special characters in a string so that it can be included in a markdown document without ...
string[] Title
Title of document.
bool TryGetFootnoteNumber(string Key, out int Number)
Tries to get the number of a footnote, given its key.
string[] Author
Author(s) of document.
string MarkdownText
Markdown text. This text might differ slightly from the original text passed to the document.
async Task RenderDocument(IRenderer Output)
Renders the document using provided output format.
Task< string > GenerateMarkdown()
Generates Markdown from the markdown text.
bool TryGetFootnote(string Key, out Footnote Footnote)
Tries to get a footnote, given its key.
string[] Next
Link to next document, in a paginated set of documents.
IEnumerator< MarkdownElement > GetEnumerator()
Gets an enumerator of root markdown elements in the document.
string[] Subtitle
Subtitle of document.
async Task GenerateHTML(StringBuilder Output, HtmlSettings HtmlSettings)
Generates HTML from the markdown text.
static Task< MarkdownDocument > Compare(MarkdownDocument Old, MarkdownDocument New, bool KeepUnchanged)
Calculates the difference of two Markdown documents.
Grade CanEncodeJson
To what extent the object supports JSON encoding.
bool SyntaxHighlighting
If syntax highlighting is used in the document.
IEnumerable< KeyValuePair< string, KeyValuePair< string, bool >[]> > MetaData
Meta-data
string[] FindHashTags()
Finds hashtags in the document.
string[] Image
Link to image for page.
bool AllowScriptTag
If client-side script tags are allowed in the document.
void QueueAsyncTask(AsyncMarkdownProcessing Callback, object State)
Queues an asynchronous task to be executed. Asynchronous tasks will be executed after the main docume...
bool TryGetMetaData(string Key, out KeyValuePair< string, bool >[] Value)
Tries to get a meta-data value given its key.
IEnumerable< MarkdownElement > Elements
Markdown elements making up the document.
string[] Privileges
Requered user privileges to display page.
void AddMetaData(string Key, string Value)
Adds meta-data to the document.
async Task GenerateMarkdown(StringBuilder Output, bool PortableSyntax)
Generates Markdown from the markdown text.
MarkdownDocument Master
Master document responsible for the current document.
MarkdownStatistics GetStatistics()
Returns some basic statistics about the contents of the Markdown object.
string[] Copyright
Link to copyright statement.
IEnumerable< string > FootnoteOrder
Order of footnotes.
bool IsDynamic
If the contents of the document is dynamic (i.e. includes script), or not (i.e. is static).
string[] Keywords
Keywords.
string[] Parameters
Name of a query parameter recognized by the page.
Task GenerateMarkdown(StringBuilder Output)
Generates Markdown from the markdown text.
string[] Previous
Link to previous document, in a paginated set of documents.
Type[] TransparentExceptionTypes
If an exception is thrown when processing script in markdown, and the exception is of any of these ty...
IEmojiSource EmojiSource
Source for emojis in the document.
string[] FindLinks()
Finds all links in the document.
static ? int HeaderEndPosition(string Markdown)
Gets the end position of the header, if one is found, null otherwise.
void ProcessAsyncTasks()
Processes any registered asynchronous tasks. This method is normally only called from renderers of do...
string[] GetMetaData(string Key)
Gets the meta-data values given a meta-data key. If meta-data is not found, an empty array is returne...
const string MarkdownSettingsVariableName
Variable name used for storing Markdown settings.
async Task GeneratePlainText(StringBuilder Output)
Generates Plain Text from the markdown text.
string[] Refresh
Tells the browser to refresh the page after a given number of seconds.
string[] MetaDataKeys
Meta-data keys availale in document.
static async Task< string > Compare(string Old, string New, MarkdownSettings Settings, bool KeepUnchanged, params Type[] TransparentExceptionTypes)
Calculates the difference of two Markdown documents.
string[] Web
Link to web page
string[] Footnotes
Gets the keys of the footnotes in the order that they are referenced in the document....
Header[] Headers
Headers in document.
string[] CSS
Link(s) to Cascading Style Sheet(s) that should be used for visual formatting of the generated HTML p...
static Task< MarkdownDocument > CreateAsync(string MarkdownText, MarkdownSettings Settings, params Type[] TransparentExceptionTypes)
Contains a markdown document. This markdown document class supports original markdown,...
string[] JavaScript
Link(s) to JavaScript files(s) that should be includedin the generated HTML page.
string[] UserVariable
Name of the variable that will hold a reference to the IUser interface for the currently logged in us...
string ResourceName
Local resource name of Markdown document, if referenced through a web server. Master documents use th...
object Tag
Property can be used to tag document with client-specific information.
string FileName
Filename of Markdown document. Markdown inclusion will be made relative to this filename.
string[] Description
Description of document.
string URL
Absolute URL of Markdown document, if referenced through a web server.
async Task< string > GenerateMarkdown(bool PortableSyntax)
Generates Markdown from the markdown text.
static Task< KeyValuePair< string, bool > > Preprocess(string Markdown, MarkdownSettings Settings, string FileName, params Type[] TransparentExceptionTypes)
Preprocesses markdown text.
MarkdownDocument Detail
Detail document of a master document.
static string AppendRows(string[] Rows, bool SingleRow)
Appends a set of rows into a single string with newlines between rows.
IEnumerable< KeyValuePair< string, Multimedia > > References
Multimedia references
async Task< string > GenerateHTML(HtmlSettings HtmlSettings)
Generates HTML from the markdown text.
static async Task< string > Preprocess(string Markdown, MarkdownSettings Settings, params Type[] TransparentExceptionTypes)
Preprocesses markdown text.
static async Task< KeyValuePair< string, bool > > Preprocess(string Markdown, MarkdownSettings Settings, string FileName, bool FromScript, params Type[] TransparentExceptionTypes)
Preprocesses markdown text.
static async Task< MarkdownDocument > CreateAsync(string MarkdownText, MarkdownSettings Settings, string FileName, string ResourceName, string URL, params Type[] TransparentExceptionTypes)
Contains a markdown document. This markdown document class supports original markdown,...
Multimedia GetReference(string Label)
Gets the multimedia information referenced by a label.
string[] Date
(Publication) date of document.
async Task< string > GeneratePlainText()
Generates Plain Text from the markdown text.
async Task< string > GenerateHTML()
Generates HTML from the markdown text.
static Task< MarkdownDocument > CreateAsync(string MarkdownText, params Type[] TransparentExceptionTypes)
Contains a markdown document. This markdown document class supports original markdown,...
string[] Login
Link to a login page. This page will be shown if the user variable does not contain a user.
Contains settings that the Markdown parser uses to customize its behavior.
string GetFileName(string DocumentFileName, string FileNameReference)
Evaluates a file name from a file reference.
Variables Variables
Collection of variables. Providing such a collection enables script execution inside markdown documen...
IEmojiSource EmojiSource
Optional Emoji source. Emojis and smileys are only available if an emoji source is provided.
AuthorizeExpression AuthorizeExpression
Optional method to call to authorize execution of script expressions.
bool ParseMetaData
If meta-data should be parsed or not.
Contains some basic statistical information about a Markdown document.
int NrElements
Number of elements in Markdown document (total).
Represents an atom of editable text (i.e. typed character).
IEditableText Source
Source
Represents a block quote in a markdown document.
Represents a bullet list in a markdown document.
Represents a center-aligned set of blocks in a markdown document.
Represents a code block in a markdown document.
Represents a definition list in a markdown document.
override void AddChildren(IEnumerable< MarkdownElement > NewChildren)
Adds children to the element.
Represents inserted blocks in a markdown document.
Represents a block of HTML in a markdown document.
Represents inserted blocks in a markdown document.
Represents a left-aligned set of blocks in a markdown document.
Represents a margin-aligned set of blocks in a markdown document.
Represents a nested block with no special formatting rules in a markdown document.
Represents a numbered item in an ordered list.
bool NumberExplicit
If number is explicitly provided (true) or inferred (false).
Represents a numbered list in a markdown document.
override void AddChildren(IEnumerable< MarkdownElement > NewChildren)
Adds children to the element.
Represents a paragraph in a markdown document.
Represents a right-aligned set of blocks in a markdown document.
Represents a sequence of sections.
Represents a table in a markdown document.
Represents a task item in a task list.
Represents a task list in a markdown document.
Represents an unnumbered item in an ordered list.
Abstract base class for all markdown elements with a variable number of child elements.
override IEnumerable< MarkdownElement > Children
Any children of the element.
void AddChildren(params MarkdownElement[] NewChildren)
Adds children to the element.
bool HasOneChild
If the element has only one child.
MarkdownElement FirstChild
First child, or null if none.
Abstract base class for all markdown elements.
override string ToString()
virtual bool ForEach(MarkdownElementHandler Callback, object State)
Loops through all child-elements for the element.
virtual bool SameMetaData(MarkdownElement E)
If the current object has same meta-data as E (but not necessarily same content).
virtual bool IsBlockElement
If the element is a block element.
abstract Task Render(IRenderer Output)
Renders the element.
virtual IEnumerable< MarkdownElement > Children
Any children of the element.
Abstract base class for all markdown elements with one child element.
MarkdownElement Child
Child element.
Represents an HTML entity.
Represents an HTML entity in Unicode format.
MultimediaItem[] Items
Multimedia items.
Renders HTML from a Markdown document.
Contains settings that the HTML export uses to customize HTML output.
Renders portable Markdown from a Markdown document.
Abstract base class for Markdown renderers.
override string ToString()
Returns the renderer output.
Renders plain text from a Markdown document.
Static class managing loading of resources stored as embedded resources or in content files.
static async Task< string > ReadAllTextAsync(string FileName)
Reads a text file asynchronously.
Helps with common XML-related tasks.
static string HtmlValueEncode(string s)
Differs from Encode(String), in that it does not encode the aposotrophe or the quote.
Generic exception, with meta-data for logging.
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Computes the difference between two sequences of symbols.
Represents an Edit-script, converting one sequence of symbols to another.
Represents a sub-sequence of symbols.
EditOperation Operation
Edit operation being performed.
T[] Symbols
Sequence of symbols.
Base class for all types of elements.
Class managing a script expression.
async Task< object > EvaluateAsync(Variables Variables)
Evaluates the expression, using the variables provided in the Variables collection....
bool ContainsImplicitPrint
If the expression contains implicit print operations.
bool ReferencesImplicitPrint(Variables Variables)
If the expression, or any function call references, contain implicit print operations.
Base class for all nodes in a parsed script tree.
string SubExpression
Sub-expression defining the node.
TextWriter ConsoleOut
Console out interface. Can be used by functions and script to output data to the console.
virtual Variable Add(string Name, object Value)
Adds a variable to the collection.
Task LockAsync()
Locks the collection. The collection is by default thread safe. But if longer transactions require un...
ValuePrinter Printer
Delegate that converts values to strings for (implicit) printing. Default is null,...
void Release()
Releases the collection, previously locked through a call to Lock().
Interface for Emoji sources. Emoji sources provide emojis to content providers.
Basic interface for resources having a FileName property.
Provides a JSON Encoding hint for an object that implements this interface.
Interface for elements containing editable text.
MarkdownElement Assemble(MarkdownDocument Document, string Text)
Assembles a markdown element from a sequence of atoms.
Interface for all markdown handlers of multimedia content.
bool EmbedInlineLink(string Url)
If the link provided should be embedded in a multi-media construct automatically.
Interface for all XML visalizers.
Task< object > TransformXml(XmlDocument Xml, Variables Variables)
Transforms the XML document before visualizing it.
Interface for code content HTML renderers.
Interface for multimedia content HTML renderers.
Interface for Markdown renderers.
Task RenderDocument(MarkdownDocument Document, bool Inclusion)
Renders a document.
Basic interface for matrices.
Interface for objects that can be converted into matrices.
TextAlignment
Text alignment of contents.
delegate bool MarkdownElementHandler(MarkdownElement Element, object State)
Delegate for markdown element callback methods.
delegate Task AsyncMarkdownProcessing(object State)
Delegate used for callback methods performing asynchronous Markdown processing
EditOperation
Type of edit-operation
Prefix
SI prefixes. http://physics.nist.gov/cuu/Units/prefixes.html
delegate Task< string > ValuePrinter(object Value, Variables Variables)
Converts a value to a printable string.