6using System.Reflection;
8using System.Text.RegularExpressions;
9using System.Threading.Tasks;
58 internal static readonly Regex endOfHeader =
new Regex(
@"\n\s*\n", RegexOptions.Multiline | RegexOptions.Compiled);
59 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);
62 private readonly Dictionary<string, Multimedia> references =
new Dictionary<string, Multimedia>();
63 private readonly Dictionary<string, KeyValuePair<string, bool>[]> metaData =
new Dictionary<string, KeyValuePair<string, bool>[]>();
64 private Dictionary<string, int> footnoteNumberByKey =
null;
65 private Dictionary<string, Footnote> footnotes =
null;
66 private SortedDictionary<int, char> toInsert =
null;
67 private readonly Type[] transparentExceptionTypes;
72 private string markdownText;
73 private string fileName =
string.Empty;
74 private string resourceName =
string.Empty;
75 private string url =
string.Empty;
79 private int lastFootnote = 0;
80 private bool syntaxHighlighting =
false;
81 private bool includesTableOfContents =
false;
82 private bool isDynamic =
false;
83 private bool? allowScriptTag =
null;
84 private object tag =
null;
138 KeyValuePair<string, bool>[] Prev;
139 bool HasProgress = !(Progress is
null);
143 int End = Blocks.Count - 1;
149 for (i = Block.Start; i <= Block.End; i++)
156 if (
string.IsNullOrEmpty(Key))
159 Values.
Add(
new KeyValuePair<string, bool>(s.Trim(), s.EndsWith(
" ")));
163 s2 = s.Substring(0, j).TrimEnd().ToUpper();
165 if (
string.IsNullOrEmpty(Key))
167 foreach (
char ch
in s2)
169 if (!
char.IsLetter(ch) && !
char.IsWhiteSpace(ch))
182 await CheckEarlyHints(Result.settings.
Progress, Key, Values);
184 if (Result.metaData.TryGetValue(Key, out Prev))
186 else if (Key ==
"LOGIN")
187 Result.isDynamic =
true;
189 Result.metaData[Key] = Values.
ToArray();
194 Values.
Add(
new KeyValuePair<string, bool>(s.Substring(j + 1).Trim(), s.EndsWith(
" ")));
198 if (!
string.IsNullOrEmpty(Key))
201 await CheckEarlyHints(Result.settings.
Progress, Key, Values);
203 if (Result.metaData.TryGetValue(Key, out Prev))
205 else if (Key ==
"LOGIN")
206 Result.isDynamic =
true;
208 Result.metaData[Key] = Values.
ToArray();
216 Result.elements = await Result.ParseBlocks(Blocks, Start, End);
221 if (!(Result.toInsert is
null))
223 StringBuilder sb =
new StringBuilder();
226 foreach (KeyValuePair<int, char> P
in Result.toInsert)
229 sb.Append(Result.markdownText.Substring(Last, P.Key - Last));
235 Result.markdownText = sb.ToString();
244 this.markdownText =
MarkdownText?.Replace(
"\r\n",
"\n").Replace(
'\r',
'\n') ??
string.Empty;
254 private static async Task CheckEarlyHints(
ICodecProgress Progress,
string Key,
255 IEnumerable<KeyValuePair<string, bool>> Values)
260 foreach (KeyValuePair<string, bool> P
in Values)
262 await Progress.
EarlyHint(P.Key,
"preload",
263 new KeyValuePair<string, string>(
"as",
"script"));
268 foreach (KeyValuePair<string, bool> P
in Values)
270 await Progress.
EarlyHint(P.Key,
"preload",
271 new KeyValuePair<string, string>(
"as",
"style"));
280 [Obsolete(
"Use GenerateMarkdown() instead.")]
302 Match M = endOfHeader.Match(Markdown);
306 string Header = Markdown.Substring(0, M.Index);
310 foreach (
string Row
in Rows)
313 if (
string.IsNullOrEmpty(s))
316 if (s.IndexOf(
':') < 0)
357 if (!
string.IsNullOrEmpty(
FileName))
359 Match M = endOfHeader.Match(Markdown);
362 s2 = Markdown.Substring(0, M.Index);
364 foreach (Match M2
in scriptHeader.Matches(s2))
368 string Tag = M2.Groups[
"Tag"].Value.ToUpper();
369 string FileName2 = M2.Groups[
"ScriptFile"].Value;
391 if (!(Prohibited is
null))
392 throw new UnauthorizedAccessException(
"Expression not permitted: " + Prohibited.
SubExpression);
406 i = Markdown.IndexOf(
"{{");
408 return new KeyValuePair<string, bool>(Markdown,
IsDynamic);
410 StringBuilder Transformed =
new StringBuilder();
412 bool UsesImplicitPrint =
false;
413 bool HasImplicitPrint =
false;
418 j = Markdown.IndexOf(
"}}", i + 2);
422 return new KeyValuePair<string, bool>(Markdown,
IsDynamic);
428 Transformed.Append(Markdown.Substring(From, i - From));
431 Script = Markdown.Substring(i + 2, j - i - 2);
440 if (!(Prohibited is
null))
441 throw new UnauthorizedAccessException(
"Expression not permitted: " + Prohibited.
SubExpression);
452 HasImplicitPrint =
true;
454 if (HasImplicitPrint)
456 UsesImplicitPrint =
true;
460 StringBuilder sb =
new StringBuilder();
462 Variables.ConsoleOut =
new StringWriter(sb);
463 Variables.Printer = PrintMarkdown;
471 Variables.ConsoleOut = Bak;
472 Variables.Printer = PrinterBak;
475 Result = sb.ToString();
484 Transformed.AppendLine(
"<font class=\"error\">");
486 if (ex is AggregateException ex2)
488 foreach (Exception ex3
in ex2.InnerExceptions)
494 Transformed.Append(
"<p>");
496 Transformed.AppendLine(
"</p>");
508 Transformed.AppendLine(
"</font>");
513 if (!(Result is
null))
515 if (!(Result is
string s3))
516 s3 = await PrintMarkdown(Result,
Variables);
518 Transformed.Append(s3);
521 i = Markdown.IndexOf(
"{{", From);
524 if (From < Markdown.Length)
525 Transformed.Append(Markdown.Substring(From));
527 return new KeyValuePair<string, bool>(Transformed.ToString(),
IsDynamic);
535 if (Value.GetType().IsValueType || Value is
string)
536 return Value.ToString();
538 if (Value is XmlDocument ||
545 Value is Exception ||
556 return Value.ToString();
559 internal void CheckException(Exception ex)
561 CheckException(ex, this.transparentExceptionTypes);
566 TypeInfo ExceptionType = ex.GetType().GetTypeInfo();
570 if (T.IsAssignableFrom(ExceptionType))
571 System.
Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw();
577 return this.ParseBlocks(Blocks, 0, Blocks.
Count - 1);
580 private async Task<ChunkedList<MarkdownElement>> ParseBlocks(
ChunkedList<Block> Blocks,
int StartBlock,
int EndBlock)
589 string InitialSectionSeparator =
null;
594 int InitialNrColumns = 1;
595 bool LastHtmlIndent =
false;
596 bool HasSections =
false;
598 for (BlockIndex = StartBlock; BlockIndex <= EndBlock; BlockIndex++)
600 Block = Blocks[BlockIndex];
602 if (Block.Indent > 0)
604 if (LastHtmlIndent || Block.Rows[Block.Start].StartsWith(
"<"))
606 LastHtmlIndent =
true;
608 Content = await this.ParseBlock(Block);
615 while (i <= EndBlock && (j = Blocks[i].Indent) > 0)
622 if (i == BlockIndex + 1)
628 while (BlockIndex < i)
633 Block = Blocks[BlockIndex++];
635 if (Block.Indent == c)
637 for (j = Block.Start; j <= Block.End; j++)
643 for (j = Block.Start; j <= Block.End; j++)
655 LastHtmlIndent =
false;
657 if (Block.IsPrefixedBy(
"```",
false))
659 s = Block.Rows[Block.Start];
661 foreach (
char ch
in s)
669 s = s.Substring(0, i);
672 while (i <= EndBlock &&
673 (!(Block = Blocks[i]).Rows[Block.End].StartsWith(s) ||
674 (i == BlockIndex && Block.Start == Block.End)))
680 bool Complete =
true;
688 for (j = BlockIndex; j <= i; j++)
692 Index = Block.Start + 1;
695 Code.
Add(
string.Empty);
699 if (j == i && Complete)
706 Code.
Add(Block.Rows[Index]);
711 Block = Blocks[BlockIndex];
712 s = Block.Rows[Block.Start].Substring(3).Trim(
'`',
' ',
'\t');
716 if (s.StartsWith(
"base64", StringComparison.CurrentCultureIgnoreCase))
720 byte[] Bin = Convert.FromBase64String(Code.Concatenate());
721 s2 = Encoding.UTF8.GetString(Bin);
723 Rows = s2.Replace(
"\r\n",
"\n").Replace(
"\r",
"\n").Split(
'\n');
741 this.syntaxHighlighting =
true;
749 if (Block.IsPrefixedBy(
">",
false))
751 if (Block.IsSuffixedBy(
"<<") && Block.IsPrefixedBy(
">>",
false))
753 AlignedBlocks = Block.RemovePrefixAndSuffix(
">>", 2,
"<<");
755 while (BlockIndex < EndBlock &&
756 (NextBlock = Blocks[BlockIndex + 1]).IsPrefixedBy(
">>",
false) &&
757 NextBlock.IsSuffixedBy(
"<<"))
760 AlignedBlocks.
AddRange(NextBlock.RemovePrefixAndSuffix(
">>", 2,
"<<"));
763 Content = await this.ParseBlocks(AlignedBlocks);
770 else if (Block.IsSuffixedBy(
">>"))
772 AlignedBlocks = Block.RemoveSuffix(
">>");
774 while (BlockIndex < EndBlock &&
775 (NextBlock = Blocks[BlockIndex + 1]).IsSuffixedBy(
">>"))
778 AlignedBlocks.
AddRange(NextBlock.RemoveSuffix(
">>"));
781 Content = await this.ParseBlocks(AlignedBlocks);
790 Content = await this.ParseBlocks(Block.RemovePrefix(
">", 2));
800 else if (Block.IsPrefixedBy(
"<<",
false))
802 if (Block.IsSuffixedBy(
">>"))
804 AlignedBlocks = Block.RemovePrefixAndSuffix(
"<<", 2,
">>");
806 while (BlockIndex < EndBlock &&
807 (NextBlock = Blocks[BlockIndex + 1]).IsPrefixedBy(
"<<",
false) &&
808 NextBlock.IsSuffixedBy(
">>"))
811 AlignedBlocks.
AddRange(NextBlock.RemovePrefixAndSuffix(
"<<", 2,
">>"));
814 Content = await this.ParseBlocks(AlignedBlocks);
823 AlignedBlocks = Block.RemovePrefix(
"<<", 2);
825 while (BlockIndex < EndBlock &&
826 (NextBlock = Blocks[BlockIndex + 1]).IsPrefixedBy(
"<<",
false))
829 AlignedBlocks.
AddRange(NextBlock.RemovePrefix(
"<<", 2));
832 Content = await this.ParseBlocks(AlignedBlocks);
842 else if (Block.IsSuffixedBy(
">>"))
844 Content = await this.ParseBlocks(Block.RemoveSuffix(
">>"));
853 else if (Block.IsPrefixedBy(
"+>",
false))
855 Content = await this.ParseBlocks(Block.RemovePrefix(
"+>", 3));
864 else if (Block.IsPrefixedBy(
"->",
false))
866 Content = await this.ParseBlocks(Block.RemovePrefix(
"->", 3));
875 else if (Block.IsPrefixedBy(
"//",
false))
877 string[] Comment =
new string[Block.End - Block.Start + 1];
879 for (i = Block.Start; i <= Block.End; i++)
880 Comment[i] = Block.Rows[i].Substring(2);
885 else if (Block.End == Block.Start && (IsUnderline(Block.Rows[0],
'-',
true,
true) || IsUnderline(Block.Rows[0],
'*',
true,
true)))
890 else if (Block.End == Block.Start && IsUnderline(Block.Rows[0],
'=',
true,
false))
892 int NrColumns = Block.Rows[0].Split(whiteSpace, StringSplitOptions.RemoveEmptyEntries).Length;
897 InitialNrColumns = NrColumns;
898 InitialSectionSeparator = Block.Rows[0];
905 else if (Block.End == Block.Start && IsUnderline(Block.Rows[0],
'~',
false,
false))
910 else if (Block.IsPrefixedBy(s2 =
"*",
true) ||
911 Block.IsPrefixedBy(s2 =
"+",
true) ||
912 Block.IsPrefixedBy(s2 =
"-",
true))
918 for (d = Block.Start + 1; d <= c; d++)
921 if (IsPrefixedBy(s, s2,
true))
923 if (Segments is
null)
926 Segments.
Add(
new Block(Block.Rows, Block.Positions, 0, i, d - 1));
931 Segments?.
Add(
new Block(Block.Rows, Block.Positions, 0, i, c));
936 if (Segments is
null)
940 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 1)
944 SubBlocks.
Add(Block);
947 Items = await this.ParseBlocks(SubBlocks);
957 Items = await this.ParseUnnumberedItems(Segments, s2);
970 if (!(LastItem is
null))
973 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 0)
981 Items = await this.ParseBlocks(Blocks, i + 1, BlockIndex);
985 if (LastItemChildren.IsBlockElement)
986 LastItemChildren.AddChildren(Items);
1007 else if (Block.IsPrefixedBy(
"#.",
true))
1013 bool Explicit =
false;
1015 for (d = Block.Start + 1; d <= c; d++)
1018 if (IsPrefixedByNumber(s, out j))
1020 if (Segments is
null)
1023 Segments.
Add(
new Tuple<int, bool, Block>(Index2, Explicit,
new Block(Block.Rows, Block.Positions, 0, i, d - 1)));
1028 else if (IsPrefixedBy(s,
"#.",
true))
1030 if (Segments is
null)
1033 Segments.
Add(
new Tuple<int, bool, Block>(Index2, Explicit,
new Block(Block.Rows, Block.Positions, 0, i, d - 1)));
1040 Segments?.
Add(
new Tuple<int, bool, Block>(Index2, Explicit,
new Block(Block.Rows, Block.Positions, 0, i, c)));
1045 if (Segments is
null)
1049 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 1)
1053 SubBlocks.
Add(Block);
1056 Items = await this.ParseBlocks(SubBlocks);
1066 Items = await this.ParseNumberedItems(Segments);
1079 if (!(LastItem is
null))
1082 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 0)
1090 Items = await this.ParseBlocks(Blocks, i + 1, BlockIndex);
1094 if (LastItemChildren.IsBlockElement)
1095 LastItemChildren.AddChildren(Items);
1116 else if (Block.IsPrefixedBy(s2 =
"[ ]",
true) ||
1117 Block.IsPrefixedBy(s2 =
"[x]",
true) ||
1118 Block.IsPrefixedBy(s2 =
"[X]",
true))
1121 int CheckPosition = Block.Positions[0] + 1;
1126 for (d = Block.Start + 1; d <= c; d++)
1129 if (IsPrefixedBy(s, s3 =
"[ ]",
true) ||
1130 IsPrefixedBy(s, s3 =
"[x]",
true) ||
1131 IsPrefixedBy(s, s3 =
"[X]",
true))
1133 if (Segments is
null)
1136 Segments.
Add(
new Tuple<Block, string, int>(
new Block(Block.Rows, Block.Positions, 0, i, d - 1), s2, CheckPosition));
1139 CheckPosition = Block.Positions[d] + 1;
1143 Segments?.
Add(
new Tuple<Block, string, int>(
new Block(Block.Rows, Block.Positions, 0, i, c), s2, CheckPosition));
1148 if (Segments is
null)
1152 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 1)
1156 SubBlocks.
Add(Block);
1159 Items = await this.ParseBlocks(SubBlocks);
1169 Items = await this.ParseTaskItems(Segments);
1177 LastItem = Items.LastItem as
TaskItem;
1182 if (!(LastItem is
null))
1185 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 0)
1193 Items = await this.ParseBlocks(Blocks, i + 1, BlockIndex);
1197 if (LastItemChildren.IsBlockElement)
1198 LastItemChildren.AddChildren(Items);
1219 else if (Block.IsPrefixedByNumber(out Index))
1224 bool Explicit =
true;
1226 for (d = Block.Start + 1; d <= c; d++)
1229 if (IsPrefixedByNumber(s, out j))
1231 if (Segments is
null)
1234 Segments.
Add(
new Tuple<int, bool, Block>(Index, Explicit,
new Block(Block.Rows, Block.Positions, 0, i, d - 1)));
1239 else if (IsPrefixedBy(s,
"#.",
true))
1241 if (Segments is
null)
1244 Segments.
Add(
new Tuple<int, bool, Block>(Index, Explicit,
new Block(Block.Rows, Block.Positions, 0, i, d - 1)));
1251 Segments?.
Add(
new Tuple<int, bool, Block>(Index, Explicit,
new Block(Block.Rows, Block.Positions, 0, i, c)));
1256 if (Segments is
null)
1259 ChunkedList<Block> SubBlocks = Block.RemovePrefix(s +
".", Math.Max(4, s.Length + 2));
1261 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 1)
1265 SubBlocks.
Add(Block);
1268 Items = await this.ParseBlocks(SubBlocks);
1278 Items = await this.ParseNumberedItems(Segments);
1291 if (!(LastItem is
null))
1294 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 0)
1302 Items = await this.ParseBlocks(Blocks, i + 1, BlockIndex);
1306 if (LastItemChildren.IsBlockElement)
1307 LastItemChildren.AddChildren(Items);
1328 else if (Block.IsTable(out TableInformation TableInformation))
1338 c = TableInformation.Columns;
1340 for (j = 0; j < TableInformation.NrHeaderRows; j++)
1342 Row = TableInformation.Headers[j];
1343 Positions = TableInformation.HeaderPositions[j];
1348 for (i = 0; i < c; i++)
1354 HeaderCellAlignments[j][i] =
null;
1358 CellElements = await this.ParseCell(Row[i], Positions[i], out HeaderCellAlignments[j][i]);
1360 if (CellElements.
Count == 1)
1364 FRef.AutoExpand =
true;
1366 if (this.footnotes.TryGetValue(FRef.Key, out
Footnote Note))
1367 Note.TableCellContents =
true;
1369 if (this.footnoteNumberByKey.TryGetValue(FRef.Key, out
int Nr) &&
1370 Nr ==
this.lastFootnote)
1372 this.footnoteNumberByKey.Remove(FRef.Key);
1373 this.lastFootnote--;
1385 for (j = 0; j < TableInformation.NrDataRows; j++)
1387 Row = TableInformation.Rows[j];
1388 Positions = TableInformation.RowPositions[j];
1393 for (i = 0; i < c; i++)
1398 DataRows[j][i] =
null;
1399 DataCellAlignments[j][i] =
null;
1403 CellElements = await this.ParseCell(Row[i], Positions[i], out DataCellAlignments[j][i]);
1405 if (CellElements.
Count == 1)
1409 FRef.AutoExpand =
true;
1411 if (this.footnotes.TryGetValue(FRef.Key, out
Footnote Note))
1412 Note.TableCellContents =
true;
1414 if (this.footnoteNumberByKey.TryGetValue(FRef.Key, out
int Nr) &&
1415 Nr ==
this.lastFootnote)
1417 this.footnoteNumberByKey.Remove(FRef.Key);
1418 this.lastFootnote--;
1422 DataRows[j][i] = CellElements.
FirstItem;
1425 DataRows[j][i] =
new NestedBlock(
this, CellElements);
1430 Elements.
Add(
new Table(
this, c,
Headers, DataRows, TableInformation.Alignments, TableInformation.AlignmentDefinitions,
1431 HeaderCellAlignments, DataCellAlignments, TableInformation.Caption, TableInformation.
Id));
1441 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 0)
1448 Description.AddRange(await this.ParseBlocks(Blocks, i + 1, BlockIndex));
1469 else if (BlockIndex < EndBlock && Blocks[BlockIndex + 1].IsPrefixedBy(
":",
true))
1476 for (i = Block.Start; i <= c; i++)
1478 Term = await this.ParseBlock(Rows, Block.Positions, i, i);
1482 if (Term.
Count == 1)
1495 else if (Block.IsFootnote(out s, out
int WhiteSparePrefix))
1498 await this.ParseBlocks(Block.RemovePrefix(
string.Empty, WhiteSparePrefix)));
1501 while (BlockIndex < EndBlock && (Block = Blocks[BlockIndex + 1]).Indent > 0)
1510 if (this.footnoteNumberByKey is
null)
1512 this.footnoteNumberByKey =
new Dictionary<string, int>();
1514 this.footnotes =
new Dictionary<string, Footnote>();
1529 if (IsUnderline(s,
'=',
false,
false))
1531 Header Header =
new Header(
this, 1,
false, s, this.PrepareHeader(await this.ParseBlock(Rows, Block.Positions, 0, c - 1)));
1533 this.headers.Add(
Header);
1536 else if (IsUnderline(s,
'-',
false,
false))
1538 Header Header =
new Header(
this, 2,
false, s, this.PrepareHeader(await this.ParseBlock(Rows, Block.Positions, 0, c - 1)));
1540 this.headers.Add(
Header);
1545 s = Rows[Block.Start];
1546 if (IsPrefixedBy(s,
'#', out d,
true) && d < s.Length)
1548 string Prefix = s.Substring(0, d);
1549 Rows[Block.Start] = s.Substring(d).Trim();
1553 while (i >= 0 && s[i] ==
'#')
1557 Rows[c] = s.Substring(0, i).TrimEnd();
1559 Header Header =
new Header(
this, d,
true, Prefix, this.PrepareHeader(await this.ParseBlock(Rows, Block.Positions, Block.Start, c)));
1561 this.headers.Add(
Header);
1565 KeyValuePair<ChunkedList<MarkdownElement>,
int> P = await this.ParseBlock(Block, Blocks, BlockIndex, EndBlock);
1567 BlockIndex = P.Value;
1575 this.settings.AllowHtml)
1579 else if (Content.
Count == 1 && Content.
FirstItem.OutsideParagraph)
1607 private async Task<ChunkedList<MarkdownElement>> ParseUnnumberedItems(
1614 while (!(Loop is
null))
1616 for (
int i = Loop.
Start, c = Loop.
Pos; i < c; i++)
1618 Loop2 = Loop[i].RemovePrefix(Prefix, 4).FirstChunk;
1620 while (!(Loop2 is
null))
1622 for (
int j = Loop2.
Start, d = Loop2.
Pos; j < d; j++)
1625 await this.ParseBlock(Loop2[j]))));
1638 private async Task<ChunkedList<MarkdownElement>> ParseNumberedItems(
1646 while (!(Loop is
null))
1648 for (
int i = Loop.
Start, c = Loop.
Pos; i < c; i++)
1650 Tuple<int, bool, Block> Segment = Loop[i];
1652 s = Segment.Item2 ? Segment.Item1.
ToString() +
"." :
"#.";
1653 Loop2 = Segment.Item3.RemovePrefix(s, Math.Max(4, s.Length + 2)).FirstChunk;
1655 while (!(Loop2 is
null))
1657 for (
int j = Loop2.
Start, d = Loop2.
Pos; j < d; j++)
1660 new NestedBlock(
this, await this.ParseBlock(Loop2[j]))));
1673 private async Task<ChunkedList<MarkdownElement>> ParseTaskItems(
ChunkedList<Tuple<Block, string, int>> Segments)
1679 while (!(Loop is
null))
1681 for (
int i = Loop.
Start, c = Loop.
Pos; i < c; i++)
1683 Tuple<Block, string, int> Segment = Loop[i];
1685 Loop2 = Segment.Item1.RemovePrefix(Segment.Item2, 4).FirstChunk;
1687 while (!(Loop2 is
null))
1689 for (
int j = Loop2.
Start, d = Loop2.
Pos; j < d; j++)
1691 Items.
Add(
new TaskItem(
this, Segment.Item2 !=
"[ ]", Segment.Item3,
1692 new NestedBlock(
this, await this.ParseBlock(Loop2[j]))));
1708 Content.
Count == 1 &&
1715 new InlineText(
this, Item.Number.ToString() +
". ")
1721 NewContent.
Add(Item.Child);
1729 private Task<ChunkedList<MarkdownElement>> ParseCell(
string Cell,
int Position, out
TextAlignment? Alignment)
1731 if (Cell.StartsWith(
"<<"))
1735 if (Cell.EndsWith(
">>"))
1738 Cell = Cell.Substring(2, Cell.Length - 4);
1743 Cell = Cell.Substring(2);
1746 else if (Cell.StartsWith(
">>") && Cell.EndsWith(
"<<"))
1749 Cell = Cell.Substring(2, Cell.Length - 4);
1752 else if (Cell.EndsWith(
">>"))
1755 Cell = Cell.Substring(0, Cell.Length - 2);
1760 return this.ParseBlock(
new string[] { Cell },
new int[] { Position });
1763 private async Task<ChunkedList<MarkdownElement>> ParseBlock(
string[] Rows,
int[] Positions)
1765 return (await this.ParseBlock(Rows, Positions, 0, Rows.Length - 1,
null, 0, 0)).Key;
1768 private async Task<ChunkedList<MarkdownElement>> ParseBlock(Block Block)
1770 return (await this.ParseBlock(Block.Rows, Block.Positions, Block.Start, Block.End,
null, 0, 0)).Key;
1773 private Task<KeyValuePair<ChunkedList<MarkdownElement>,
int>> ParseBlock(Block Block,
ChunkedList<Block> Blocks,
int BlockIndex,
int EndBlock)
1775 return this.ParseBlock(Block.Rows, Block.Positions, Block.Start, Block.End, Blocks, BlockIndex, EndBlock);
1778 private async Task<ChunkedList<MarkdownElement>> ParseBlock(
string[] Rows,
int[] Positions,
int StartRow,
int EndRow)
1780 return (await this.ParseBlock(Rows, Positions, StartRow, EndRow,
null, 0, 0)).Key;
1783 private async Task<KeyValuePair<ChunkedList<MarkdownElement>,
int>> ParseBlock(
string[] Rows,
int[] Positions,
int StartRow,
int EndRow,
ChunkedList<Block> Blocks,
1784 int BlockIndex,
int EndBlock)
1787 bool PreserveCrLf = Rows[StartRow].StartsWith(
"<") && Rows[EndRow].EndsWith(
">");
1788 BlockParseState State =
new BlockParseState(Rows, Positions, StartRow, EndRow, PreserveCrLf, Blocks, BlockIndex, EndBlock);
1790 await this.ParseBlock(State, (
char)0, 1,
Elements,
true);
1792 return new KeyValuePair<ChunkedList<MarkdownElement>,
int>(
Elements, State.BlockIndex);
1795 private async Task<bool> ParseBlock(BlockParseState State,
char TerminationCharacter,
int TerminationCharacterCount,
1799 StringBuilder Text =
new StringBuilder();
1802 char PrevChar =
' ';
1805 bool FirstCharOnLine;
1807 while ((ch = State.NextChar()) != (
char)0)
1809 if (ch == TerminationCharacter)
1811 if (TerminationCharacterCount == 1 ||
1812 State.CheckRestOfTermination(TerminationCharacter, TerminationCharacterCount - 1))
1821 this.AppendAnyText(
Elements, Text);
1830 if (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
1832 if (State.IsFirstCharOnLine)
1834 this.AppendAnyText(
Elements, Text);
1836 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
1837 State.NextCharSameRow();
1843 State.CurrentPosition
1846 Rows.
Add(State.RestOfRow());
1850 if ((ch2 = State.PeekNextCharSameRow()) ==
'*' || ch2 ==
'+' || ch2 ==
'-')
1859 State.NextCharSameRow();
1860 State.SkipWhitespaceSameRow(3);
1865 Positions.
Add(State.CurrentPosition);
1866 Rows.
Add(State.RestOfRow());
1870 State.SkipWhitespaceSameRow(4);
1872 Positions.
Add(State.CurrentPosition);
1873 Rows.
Add(State.RestOfRow());
1893 this.AppendAnyText(
Elements, Text);
1895 ch2 = State.PeekNextCharSameRow();
1898 State.NextCharSameRow();
1900 await this.ParseBlock(State,
'*', 2, ChildElements,
true);
1905 if (this.emojiSource is
null)
1911 State.NextCharSameRow();
1916 State.BackupState();
1917 State.NextCharSameRow();
1919 if (State.PeekNextCharSameRow() ==
')')
1921 State.DiscardBackup();
1922 State.NextCharSameRow();
1927 State.RestoreState();
1929 if (await this.ParseBlock(State,
'*', 1, ChildElements, TerminationCharacter !=
'*'))
1932 this.FixSyntaxError(
Elements,
"*", ChildElements);
1937 State.BackupState();
1938 State.NextCharSameRow();
1939 if ((ch3 = State.NextCharSameRow()) ==
'0' || ch3 ==
'O')
1941 if (State.NextCharSameRow() ==
'/')
1943 if (State.NextCharSameRow() ==
'*')
1945 State.DiscardBackup();
1946 this.AppendAnyText(
Elements, Text);
1953 State.RestoreState();
1954 if (await this.ParseBlock(State,
'*', 1, ChildElements, TerminationCharacter !=
'*'))
1957 this.FixSyntaxError(
Elements,
"*", ChildElements);
1962 if (await this.ParseBlock(State,
'*', 1, ChildElements, TerminationCharacter !=
'*'))
1965 this.FixSyntaxError(
Elements,
"*", ChildElements);
1972 if ((ch2 = State.PeekNextCharSameRow()) <=
' ' || ch2 == 160)
1978 this.AppendAnyText(
Elements, Text);
1980 ch2 = State.PeekNextCharSameRow();
1983 State.NextCharSameRow();
1985 await this.ParseBlock(State,
'_', 2, ChildElements,
true);
1990 if (await this.ParseBlock(State,
'_', 1, ChildElements, TerminationCharacter !=
'_'))
1993 this.FixSyntaxError(
Elements,
"_", ChildElements);
1998 if ((ch2 = State.PeekNextCharSameRow()) <=
' ' || ch2 == 160)
2004 this.AppendAnyText(
Elements, Text);
2006 ch2 = State.PeekNextCharSameRow();
2009 State.NextCharSameRow();
2011 await this.ParseBlock(State,
'~', 2, ChildElements,
true);
2016 if (await this.ParseBlock(State,
'~', 1, ChildElements, TerminationCharacter !=
'~'))
2019 this.FixSyntaxError(
Elements,
"~", ChildElements);
2024 this.AppendAnyText(
Elements, Text);
2025 ch2 = State.PeekNextCharSameRow();
2028 State.NextCharSameRow();
2030 while ((ch2 = State.NextChar()) != 0)
2032 if (ch2 ==
'`' && State.PeekNextCharSameRow() ==
'`')
2034 State.NextCharSameRow();
2043 while ((ch2 = State.NextChar()) !=
'`' && ch2 != 0)
2053 FirstCharOnLine = State.IsFirstCharOnLine;
2057 ch2 = State.PeekNextCharSameRow();
2064 State.NextCharSameRow();
2068 ch2 = State.PeekNextCharSameRow();
2071 State.NextCharSameRow();
2072 this.AppendAnyText(
Elements, Text);
2076 else if (ch2 ==
'%')
2078 State.NextCharSameRow();
2079 this.AppendAnyText(
Elements, Text);
2081 while ((ch3 = State.NextCharSameRow()) !=
']' && ch3 != 0)
2086 Url = Text.ToString();
2087 if (
string.
Compare(Url,
"Details",
true) == 0)
2094 Text.Insert(0,
"[%");
2098 else if (ch2 ==
'^')
2100 State.NextCharSameRow();
2101 this.AppendAnyText(
Elements, Text);
2103 while ((ch3 = State.NextChar()) !=
']' && ch3 != 0)
2108 Url = Text.ToString();
2111 if (this.footnoteNumberByKey is
null)
2113 this.footnoteNumberByKey =
new Dictionary<string, int>();
2115 this.footnotes =
new Dictionary<string, Footnote>();
2120 Title = Url.ToLower();
2122 if (!this.footnoteNumberByKey.ContainsKey(
Title))
2124 this.footnoteNumberByKey[
Title] = ++this.lastFootnote;
2130 Title = Guid.NewGuid().ToString();
2133 this.footnoteNumberByKey[
Title] = ++this.lastFootnote;
2135 this.footnotes[
Title] =
new Footnote(
this,
Title,
new Paragraph(
this, await this.ParseBlock(
new string[] { Url },
new int[] { State.CurrentPosition - 1 - Url.Length })));
2139 Text.Insert(0,
"[^");
2147 if (FirstCharOnLine && (((chs = State.PeekNextChars(3))[0] ==
' ' || chs[0] ==
'x' || chs[0] ==
'X') && chs[1] ==
']' && ((chs[2] <=
' ' && chs[2] > 0) || chs[2] == 160)))
2149 int CheckPosition = State.CurrentPosition;
2155 this.AppendAnyText(
Elements, Text);
2157 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
2158 State.NextCharSameRow();
2167 State.CurrentPosition
2169 bool Checked = (chs[0] !=
' ');
2173 if ((chs = State.PeekNextChars(4))[0] ==
'[' &&
2174 (chs[1] ==
' ' || chs[1] ==
'x' || chs[1] ==
'X') &&
2175 chs[2] ==
']' && ((chs[3] <=
' ' && chs[3] > 0) || chs[3] == 160))
2177 Item =
new TaskItem(
this, Checked, CheckPosition,
2190 CheckPosition = State.CurrentPosition;
2196 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
2197 State.NextCharSameRow();
2199 Positions.
Add(State.CurrentPosition);
2200 Rows.
Add(State.RestOfRow());
2202 Checked = (chs[1] !=
' ');
2206 State.SkipWhitespaceSameRow(4);
2207 Positions.
Add(State.CurrentPosition);
2208 Rows.
Add(State.RestOfRow());
2214 Item =
new TaskItem(
this, Checked, CheckPosition,
2227 this.AppendAnyText(
Elements, Text);
2229 if (await this.ParseBlock(State,
']', 1, ChildElements,
false))
2231 ch2 = State.PeekNextNonWhitespaceChar(
false);
2234 State.NextNonWhitespaceChar();
2235 Title =
string.Empty;
2237 while ((ch2 = State.PeekNextCharSameRow()) != 0 && ch2 >
' ' && ch2 !=
')' && ch2 != 160)
2243 Url = Text.ToString();
2244 if (Url.StartsWith(
"abbr:", StringComparison.CurrentCultureIgnoreCase))
2250 while ((ch2 = State.NextCharSameRow()) != 0 && ch2 !=
')')
2254 Url = Text.ToString();
2263 if (Url.StartsWith(
"<") && Url.EndsWith(
">"))
2264 Url = Url.Substring(1, Url.Length - 2);
2266 if (ch2 <=
' ' || ch2 == 160)
2268 ch2 = State.PeekNextNonWhitespaceChar(
true);
2270 if (ch2 ==
'"' || ch2 ==
'\'')
2272 State.NextNonWhitespaceChar();
2273 while ((ch3 = State.NextCharSameRow()) != 0 && ch3 != ch2)
2276 Title = Text.ToString();
2279 ch2 = State.PeekNextNonWhitespaceChar(
true);
2282 Title =
string.Empty;
2285 if (ch ==
'!' && ch2 !=
')')
2287 ParseWidthHeight(State, out Width, out Height);
2288 ch2 = State.PeekNextCharSameRow();
2291 Width = Height =
null;
2293 while (ch2 != 0 && ch2 !=
')')
2295 State.NextCharSameRow();
2296 ch2 = State.PeekNextCharSameRow();
2309 if (!this.includesTableOfContents &&
string.
Compare(Url,
"ToC",
true) == 0)
2310 this.includesTableOfContents =
true;
2312 State.BackupState();
2313 ch2 = State.PeekNextNonWhitespaceChar(
false);
2317 State.NextNonWhitespaceChar();
2318 Title =
string.Empty;
2320 while ((ch2 = State.PeekNextCharSameRow()) != 0 && ch2 >
' ' && ch2 !=
')' && ch2 != 160)
2326 Url = Text.ToString();
2330 if (Url.StartsWith(
"<") && Url.EndsWith(
">"))
2331 Url = Url.Substring(1, Url.Length - 2);
2333 if (ch2 <=
' ' || ch2 == 160)
2335 ch2 = State.PeekNextNonWhitespaceChar(
true);
2337 if (ch2 ==
'"' || ch2 ==
'\'')
2339 State.NextNonWhitespaceChar();
2340 while ((ch3 = State.NextCharSameRow()) != 0 && ch3 != ch2)
2343 Title = Text.ToString();
2346 ch2 = State.PeekNextNonWhitespaceChar(
true);
2349 Title =
string.Empty;
2354 ParseWidthHeight(State, out Width, out Height);
2356 ch2 = State.PeekNextCharSameRow();
2358 while (ch2 != 0 && ch2 !=
')')
2360 State.NextCharSameRow();
2361 ch2 = State.PeekNextCharSameRow();
2370 ch2 = State.PeekNextNonWhitespaceChar(
true);
2373 State.DiscardBackup();
2374 State.BackupState();
2377 State.RestoreState();
2385 if (!(this.settings?.Progress is
null))
2396 else if (ch2 ==
':' && FirstCharOnLine)
2398 State.NextNonWhitespaceChar();
2399 ch2 = State.NextChar();
2400 while ((ch2 != 0 && ch2 <=
' ') || ch2 == 160)
2401 ch2 = State.NextChar();
2403 if (ch2 >
' ' && ch2 != 160)
2409 while (ch2 >
' ' && ch2 != 160 && ch2 !=
'[')
2411 ch2 = State.NextNonWhitespaceChar();
2412 while (ch2 != 0 && ch2 >
' ' && ch2 != 160)
2415 ch2 = State.NextCharSameRow();
2418 Url = Text.ToString();
2421 if (Url.StartsWith(
"<") && Url.EndsWith(
">"))
2422 Url = Url.Substring(1, Url.Length - 2);
2424 ch2 = State.PeekNextNonWhitespaceChar(
true);
2426 if (ch2 ==
'"' || ch2 ==
'\'' || ch2 ==
'(')
2428 State.NextNonWhitespaceChar();
2432 while ((ch3 = State.NextCharSameRow()) != 0 && ch3 != ch2)
2435 Title = Text.ToString();
2439 Title =
string.Empty;
2441 ParseWidthHeight(State, out Width, out Height);
2444 if (!this.includesTableOfContents &&
string.
Compare(Url,
"ToC",
true) == 0)
2445 this.includesTableOfContents =
true;
2447 ch2 = State.PeekNextNonWhitespaceChar(
true);
2458 this.references[Text.ToString().ToLower()] =
Multimedia;
2460 if (!(this.settings?.Progress is
null))
2470 else if (ch2 ==
'[')
2472 State.NextNonWhitespaceChar();
2473 while ((ch2 = State.NextCharSameRow()) != 0 && ch2 !=
']')
2476 Title = Text.ToString();
2479 if (
string.IsNullOrEmpty(
Title))
2486 Title = Text.ToString();
2502 this.FixSyntaxError(
Elements,
"![", ChildElements);
2511 this.FixSyntaxError(
Elements, ch ==
'!' ?
"![" :
"[", ChildElements);
2515 ch2 = State.PeekNextCharSameRow();
2518 State.NextCharSameRow();
2519 this.AppendAnyText(
Elements, Text);
2527 ch2 = State.PeekNextCharSameRow();
2530 State.NextCharSameRow();
2531 this.AppendAnyText(
Elements, Text);
2533 ch3 = State.PeekNextCharSameRow();
2536 State.NextCharSameRow();
2543 else if (ch2 ==
'-')
2545 State.NextCharSameRow();
2546 ch3 = State.PeekNextCharSameRow();
2550 State.NextCharSameRow();
2551 this.AppendAnyText(
Elements, Text);
2553 ch3 = State.PeekNextCharSameRow();
2556 State.NextCharSameRow();
2566 else if (ch2 ==
'=')
2568 State.NextCharSameRow();
2569 this.AppendAnyText(
Elements, Text);
2570 ch3 = State.PeekNextCharSameRow();
2574 State.NextCharSameRow();
2576 ch3 = State.PeekNextCharSameRow();
2579 State.NextCharSameRow();
2589 else if (ch2 ==
'>')
2591 State.NextCharSameRow();
2592 this.AppendAnyText(
Elements, Text);
2596 else if (ch2 ==
'3' && !(this.emojiSource is
null))
2598 State.NextCharSameRow();
2599 this.AppendAnyText(
Elements, Text);
2603 else if (ch2 ==
'/')
2605 State.NextCharSameRow();
2606 if (!(this.emojiSource is
null) && State.PeekNextCharSameRow() ==
'3')
2608 State.NextCharSameRow();
2609 this.AppendAnyText(
Elements, Text);
2615 if ((!
char.IsLetter(ch2) && ch2 !=
'/') || !this.settings.AllowHtml)
2621 this.AppendAnyText(
Elements, Text);
2627 while ((ch2 = State.NextChar()) != 0 && ch2 !=
'>')
2639 Url = Text.ToString();
2641 if (Url.StartsWith(
"</"))
2643 if (Url.StartsWith(
"</script", StringComparison.CurrentCultureIgnoreCase))
2648 else if (Url.StartsWith(
"<script", StringComparison.CurrentCultureIgnoreCase))
2652 Text.Append(State.UntilToken(
"</SCRIPT>"));
2654 Text.Append(Url.Substring(1, 6));
2662 else if (Url.StartsWith(
"<textarea", StringComparison.CurrentCultureIgnoreCase))
2666 string s = State.UntilToken(
"</TEXTAREA>");
2668 if (!
string.IsNullOrEmpty(s))
2675 int i = Url.IndexOf(
' ');
2677 if ((i < 0 && Url.IndexOf(
':') >= 0) || (i > 0 && Url.LastIndexOf(
':', i) >= 0))
2679 else if ((i < 0 && Url.IndexOf(
'@') >= 0) || (i > 0 && Url.LastIndexOf(
'@', i) >= 0))
2685 if (Url.StartsWith(
"<textarea", StringComparison.CurrentCultureIgnoreCase))
2687 string s = State.UntilToken(
"</TEXTAREA>");
2689 if (!
string.IsNullOrEmpty(s))
2701 switch (State.PeekNextCharSameRow())
2704 State.NextCharSameRow();
2705 this.AppendAnyText(
Elements, Text);
2707 ch3 = State.PeekNextCharSameRow();
2710 State.NextCharSameRow();
2718 this.AppendAnyText(
Elements, Text);
2719 State.NextCharSameRow();
2721 if (!(this.emojiSource is
null) && State.PeekNextCharSameRow() ==
')')
2723 State.NextCharSameRow();
2731 if (!(this.emojiSource is
null))
2733 State.NextCharSameRow();
2734 switch (State.PeekNextCharSameRow())
2737 State.NextCharSameRow();
2738 this.AppendAnyText(
Elements, Text);
2743 State.NextCharSameRow();
2744 this.AppendAnyText(
Elements, Text);
2749 State.NextCharSameRow();
2750 this.AppendAnyText(
Elements, Text);
2755 State.NextCharSameRow();
2756 this.AppendAnyText(
Elements, Text);
2765 State.NextCharSameRow();
2766 this.AppendAnyText(
Elements, Text);
2773 State.NextCharSameRow();
2774 this.AppendAnyText(
Elements, Text);
2781 State.NextCharSameRow();
2782 this.AppendAnyText(
Elements, Text);
2787 State.NextCharSameRow();
2788 switch (State.PeekNextCharSameRow())
2791 State.NextCharSameRow();
2792 this.AppendAnyText(
Elements, Text);
2797 State.NextCharSameRow();
2798 this.AppendAnyText(
Elements, Text);
2818 if (!(this.emojiSource is
null))
2820 State.NextCharSameRow();
2821 if (State.PeekNextCharSameRow() ==
')')
2823 State.NextCharSameRow();
2824 this.AppendAnyText(
Elements, Text);
2835 if (!(this.emojiSource is
null))
2837 State.NextCharSameRow();
2838 if (State.PeekNextCharSameRow() ==
'<')
2840 State.NextCharSameRow();
2841 this.AppendAnyText(
Elements, Text);
2858 if (!this.settings.AllowInlineScript ||
this.settings.Variables is
null)
2860 int Pos = State.CurrentPosition - 1;
2861 if (Pos < this.markdownText.Length &&
this.markdownText[Pos] ==
'{')
2863 if (this.toInsert is
null)
2864 this.toInsert =
new SortedDictionary<int, char>();
2866 this.toInsert[Pos] =
'\\';
2867 if (Pos > 0 && ((ch2 = this.markdownText[Pos - 1]) ==
':' || ch2 ==
'*' || ch2 ==
'='))
2868 this.toInsert[Pos - 1] =
'\\';
2874 this.AppendAnyText(
Elements, Text);
2875 State.BackupState();
2877 int StartPosition = State.CurrentPosition - 1;
2879 while ((ch2 = State.NextChar()) !=
'}' && ch2 != 0)
2882 int EndPosition = State.CurrentPosition;
2886 State.RestoreState();
2894 State.DiscardBackup();
2896 this.settings.ScriptContext);
2901 this.isDynamic =
true;
2903 catch (Exception ex)
2908 new InlineHTML(
this,
"<font class=\"error\">"))));
2910 if (ex is AggregateException ex2)
2912 foreach (Exception ex3
in ex2.InnerExceptions)
2914 this.CheckException(ex3);
2924 this.CheckException(ex);
2935 this.CheckException(ex);
2941 ch2 = State.PeekNextCharSameRow();
2944 State.NextCharSameRow();
2945 this.AppendAnyText(
Elements, Text);
2947 ch3 = State.PeekNextCharSameRow();
2951 State.NextCharSameRow();
2954 else if (ch3 ==
'-')
2956 State.NextCharSameRow();
2962 else if (ch2 ==
'+')
2964 State.NextCharSameRow();
2965 this.AppendAnyText(
Elements, Text);
2968 else if (ch2 ==
'_')
2970 if (!(this.emojiSource is
null))
2972 State.BackupState();
2973 while ((ch2 = State.NextCharSameRow()) ==
'_')
2978 State.DiscardBackup();
2979 State.NextCharSameRow();
2980 this.AppendAnyText(
Elements, Text);
2985 State.RestoreState();
2992 else if ((ch2 <= ' ' && ch2 > 0) || ch2 == 160)
2994 if (State.IsFirstCharOnLine)
2996 this.AppendAnyText(
Elements, Text);
2998 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
2999 State.NextCharSameRow();
3005 State.CurrentPosition
3008 Rows.
Add(State.RestOfRow());
3012 if ((ch2 = State.PeekNextCharSameRow()) ==
'*' || ch2 ==
'+' || ch2 ==
'-')
3021 State.NextCharSameRow();
3022 State.SkipWhitespaceSameRow(3);
3027 Positions.
Add(State.CurrentPosition);
3028 Rows.
Add(State.RestOfRow());
3032 State.SkipWhitespaceSameRow(4);
3034 Positions.
Add(State.CurrentPosition);
3035 Rows.
Add(State.RestOfRow());
3057 ch2 = State.PeekNextCharSameRow();
3060 State.NextCharSameRow();
3061 this.AppendAnyText(
Elements, Text);
3064 else if ((ch2 <= ' ' && ch2 > 0) || ch2 == 160)
3066 if (State.IsFirstCharOnLine)
3068 this.AppendAnyText(
Elements, Text);
3070 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
3071 State.NextCharSameRow();
3077 State.CurrentPosition
3080 Rows.
Add(State.RestOfRow());
3084 if ((ch2 = State.PeekNextCharSameRow()) ==
'*' || ch2 ==
'+' || ch2 ==
'-')
3093 State.NextCharSameRow();
3094 State.SkipWhitespaceSameRow(3);
3099 Positions.
Add(State.CurrentPosition);
3100 Rows.
Add(State.RestOfRow());
3104 State.SkipWhitespaceSameRow(4);
3106 Positions.
Add(State.CurrentPosition);
3107 Rows.
Add(State.RestOfRow());
3129 ch2 = State.PeekNextCharSameRow();
3130 if (
char.IsLetterOrDigit(ch2))
3132 this.AppendAnyText(
Elements, Text);
3135 State.NextCharSameRow();
3137 while (
char.IsLetterOrDigit(ch2 = State.PeekNextCharSameRow()))
3140 State.NextCharSameRow();
3146 else if (State.IsFirstCharOnLine && ch2 ==
'.')
3148 State.NextCharSameRow();
3150 if (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
3152 this.AppendAnyText(
Elements, Text);
3154 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
3155 State.NextCharSameRow();
3161 State.CurrentPosition
3164 Rows.
Add(State.RestOfRow());
3168 if (State.PeekNextCharSameRow() ==
'#')
3170 State.NextCharSameRow();
3171 if (State.PeekNextCharSameRow() ==
'.')
3180 State.NextCharSameRow();
3181 State.SkipWhitespaceSameRow(3);
3186 Positions.
Add(State.CurrentPosition);
3187 Rows.
Add(State.RestOfRow());
3191 State.SkipWhitespaceSameRow(4);
3193 Positions.
Add(State.CurrentPosition - 1);
3194 Rows.
Add(
"#" + State.RestOfRow());
3199 State.SkipWhitespaceSameRow(4);
3201 Positions.
Add(State.CurrentPosition);
3202 Rows.
Add(State.RestOfRow());
3218 Item.Number = PrevItem.Number + 1;
3228 else if (!(this.emojiSource is
null))
3230 switch (State.PeekNextCharSameRow())
3233 State.BackupState();
3234 State.NextCharSameRow();
3235 switch (State.PeekNextCharSameRow())
3238 State.DiscardBackup();
3239 State.NextCharSameRow();
3240 this.AppendAnyText(
Elements, Text);
3245 State.RestoreState();
3252 State.NextCharSameRow();
3253 this.AppendAnyText(
Elements, Text);
3276 if (!(this.emojiSource is
null) && (ch ==
'8' || ch ==
'0') && (
char.IsPunctuation(PrevChar) ||
char.IsWhiteSpace(PrevChar)))
3280 switch (ch2 = State.PeekNextCharSameRow())
3283 State.BackupState();
3284 State.NextCharSameRow();
3285 switch (State.PeekNextCharSameRow())
3289 State.DiscardBackup();
3290 State.NextCharSameRow();
3291 this.AppendAnyText(
Elements, Text);
3297 State.NextCharSameRow();
3298 switch (State.PeekNextCharSameRow())
3302 State.DiscardBackup();
3303 State.NextCharSameRow();
3304 this.AppendAnyText(
Elements, Text);
3310 State.RestoreState();
3316 State.RestoreState();
3322 State.BackupState();
3323 State.NextCharSameRow();
3324 switch (State.PeekNextCharSameRow())
3328 State.NextCharSameRow();
3329 switch (State.PeekNextCharSameRow())
3332 State.DiscardBackup();
3333 State.NextCharSameRow();
3334 this.AppendAnyText(
Elements, Text);
3340 State.RestoreState();
3346 State.RestoreState();
3357 switch (ch2 = State.PeekNextCharSameRow())
3360 State.BackupState();
3361 State.NextCharSameRow();
3362 switch (State.PeekNextCharSameRow())
3366 State.DiscardBackup();
3367 State.NextCharSameRow();
3368 this.AppendAnyText(
Elements, Text);
3374 State.RestoreState();
3380 State.NextCharSameRow();
3381 this.AppendAnyText(
Elements, Text);
3391 if (ch2 == (
char)0xffff)
3395 if (State.IsFirstCharOnLine)
3397 StringBuilder sb =
new StringBuilder();
3400 while ((ch2 = State.PeekNextCharSameRow()) >=
'0' && ch2 <=
'9')
3402 State.NextCharSameRow();
3408 State.NextCharSameRow();
3409 if ((((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160) &&
3410 int.TryParse(sb.ToString(), out
int Index))
3412 this.AppendAnyText(
Elements, Text);
3414 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
3415 State.NextCharSameRow();
3421 State.CurrentPosition
3424 Rows.
Add(State.RestOfRow());
3428 if ((ch2 = State.PeekNextCharSameRow()) >=
'0' && ch2 <=
'9')
3431 while ((ch2 = State.NextCharSameRow()) >=
'0' && ch2 <=
'9')
3434 if (ch2 ==
'.' &&
int.TryParse(sb.ToString(), out
int Index2))
3443 State.NextCharSameRow();
3444 State.SkipWhitespaceSameRow(3);
3449 Positions.
Add(State.CurrentPosition);
3450 Rows.
Add(State.RestOfRow());
3455 State.SkipWhitespaceSameRow(4);
3457 string s = sb.ToString();
3458 Positions.
Add(State.CurrentPosition - 1 - s.Length);
3459 Rows.
Add(s + ch2 + State.RestOfRow());
3464 State.SkipWhitespaceSameRow(4);
3466 Positions.
Add(State.CurrentPosition);
3467 Rows.
Add(State.RestOfRow());
3483 Text.Append(sb.ToString());
3488 Text.Append(sb.ToString());
3495 ch2 = State.PeekNextCharSameRow();
3496 if (this.emojiSource is
null && ch2 !=
'=')
3502 State.NextCharSameRow();
3503 this.AppendAnyText(
Elements, Text);
3505 ch3 = State.PeekNextCharSameRow();
3508 State.NextCharSameRow();
3516 State.NextCharSameRow();
3517 this.AppendAnyText(
Elements, Text);
3523 State.NextCharSameRow();
3524 this.AppendAnyText(
Elements, Text);
3529 State.NextCharSameRow();
3530 this.AppendAnyText(
Elements, Text);
3536 State.NextCharSameRow();
3537 this.AppendAnyText(
Elements, Text);
3542 State.NextCharSameRow();
3543 this.AppendAnyText(
Elements, Text);
3550 State.NextCharSameRow();
3551 this.AppendAnyText(
Elements, Text);
3560 State.NextCharSameRow();
3561 this.AppendAnyText(
Elements, Text);
3568 State.NextCharSameRow();
3569 this.AppendAnyText(
Elements, Text);
3580 if (
char.IsLetter(ch2 = State.PeekNextCharSameRow()))
3582 this.AppendAnyText(
Elements, Text);
3585 while (
char.IsLetter(ch2 = State.NextCharSameRow()))
3594 Url = Text.ToString();
3599 else if (ch2 ==
'#')
3603 this.AppendAnyText(
Elements, Text);
3604 State.NextCharSameRow();
3608 if ((ch3 = State.PeekNextCharSameRow()) ==
'x' || ch3 ==
'X')
3611 State.NextCharSameRow();
3613 while (((ch3 =
char.ToUpper(State.PeekNextCharSameRow())) >=
'0' && ch3 <=
'9') || (ch3 >=
'A' && ch3 <=
'F'))
3615 State.NextCharSameRow();
3619 if (ch3 ==
';' &&
int.TryParse(Text.ToString().Substring(3),
System.Globalization.NumberStyles.HexNumber,
null, out Code))
3621 State.NextCharSameRow();
3627 else if (
char.IsDigit(ch3))
3629 while (
char.IsDigit(ch3 = State.PeekNextCharSameRow()))
3631 State.NextCharSameRow();
3635 if (ch3 ==
';' &&
int.TryParse(Text.ToString().Substring(2), out Code))
3637 State.NextCharSameRow();
3650 this.AppendAnyText(
Elements, Text);
3651 if (IsLeftQuote(PrevChar, State.PeekNextCharSameRow()))
3658 this.AppendAnyText(
Elements, Text);
3660 if (!(this.emojiSource is
null))
3661 ch2 = State.PeekNextCharSameRow();
3668 State.NextCharSameRow();
3669 switch (State.PeekNextCharSameRow())
3673 State.NextCharSameRow();
3678 State.NextCharSameRow();
3683 State.NextCharSameRow();
3684 switch (State.PeekNextCharSameRow())
3688 State.NextCharSameRow();
3693 State.NextCharSameRow();
3698 if (IsLeftQuote(PrevChar, State.PeekNextCharSameRow()))
3709 if (IsLeftQuote(PrevChar, State.PeekNextCharSameRow()))
3720 State.NextCharSameRow();
3721 switch (State.PeekNextCharSameRow())
3725 State.NextCharSameRow();
3730 State.NextCharSameRow();
3735 if (IsLeftQuote(PrevChar, State.PeekNextCharSameRow()))
3746 if (IsLeftQuote(PrevChar, State.PeekNextCharSameRow()))
3755 if (State.PeekNextCharSameRow() ==
'.')
3757 State.NextCharSameRow();
3758 if (State.PeekNextCharSameRow() ==
'.')
3760 State.NextCharSameRow();
3761 this.AppendAnyText(
Elements, Text);
3773 ch2 = State.PeekNextCharSameRow();
3774 ch3 =
char.ToLower(ch2);
3775 if (ch3 ==
'c' || ch3 ==
'r' || ch3 ==
'p' || ch3 ==
's')
3777 State.NextCharSameRow();
3778 if (State.PeekNextCharSameRow() ==
')')
3780 State.NextCharSameRow();
3782 this.AppendAnyText(
Elements, Text);
3835 switch (State.PeekNextCharSameRow())
3838 State.NextCharSameRow();
3839 this.AppendAnyText(
Elements, Text);
3841 ch3 = State.PeekNextCharSameRow();
3844 State.NextCharSameRow();
3852 if (!(this.emojiSource is
null))
3854 State.BackupState();
3855 State.NextCharSameRow();
3856 switch (State.PeekNextCharSameRow())
3859 State.DiscardBackup();
3860 State.NextCharSameRow();
3861 this.AppendAnyText(
Elements, Text);
3866 State.RestoreState();
3876 if (!(this.emojiSource is
null))
3878 State.NextCharSameRow();
3879 this.AppendAnyText(
Elements, Text);
3893 ch2 = State.PeekNextCharSameRow();
3897 State.NextCharSameRow();
3898 this.AppendAnyText(
Elements, Text);
3903 State.NextCharSameRow();
3904 this.AppendAnyText(
Elements, Text);
3909 State.NextCharSameRow();
3910 this.AppendAnyText(
Elements, Text);
3915 State.NextCharSameRow();
3916 this.AppendAnyText(
Elements, Text);
3921 State.NextCharSameRow();
3922 this.AppendAnyText(
Elements, Text);
3927 State.NextCharSameRow();
3928 this.AppendAnyText(
Elements, Text);
3983 State.NextCharSameRow();
3984 this.AppendAnyText(
Elements, Text);
3989 State.NextCharSameRow();
3990 this.AppendAnyText(
Elements, Text);
3992 if (State.PeekNextCharSameRow() ==
'M')
3994 State.NextCharSameRow();
4002 State.NextCharSameRow();
4003 this.AppendAnyText(
Elements, Text);
4005 if (State.PeekNextCharSameRow() ==
't')
4007 State.NextCharSameRow();
4015 State.NextCharSameRow();
4016 this.AppendAnyText(
Elements, Text);
4018 if (State.PeekNextCharSameRow() ==
'd')
4020 State.NextCharSameRow();
4028 State.NextCharSameRow();
4029 this.AppendAnyText(
Elements, Text);
4031 if (State.PeekNextCharSameRow() ==
'd')
4033 State.NextCharSameRow();
4041 State.NextCharSameRow();
4042 this.AppendAnyText(
Elements, Text);
4044 if (State.PeekNextCharSameRow() ==
'h')
4046 State.NextCharSameRow();
4054 State.NextCharSameRow();
4055 this.AppendAnyText(
Elements, Text);
4059 await this.ParseBlock(State,
')', 1, ChildElements,
true);
4064 State.NextCharSameRow();
4065 this.AppendAnyText(
Elements, Text);
4069 await this.ParseBlock(State,
']', 1, ChildElements,
true);
4080 if ((ch2 = State.PeekNextCharSameRow()) <=
' ' || ch2 == 160)
4082 if (State.IsFirstCharOnLine && ch2 > 0)
4089 for (i = State.Start; i < State.Current; i++)
4091 Item = await this.ParseBlock(State.Rows, State.Positions, i, i);
4095 if (TotItem is
null)
4097 if (Item.
Count == 1)
4104 if (TotItem is
null)
4111 if (TotItem is
null)
4121 while (((ch2 = State.PeekNextCharSameRow()) <=
' ' && ch2 > 0) || ch2 == 160)
4122 State.NextCharSameRow();
4127 State.CurrentPosition
4130 Rows.
Add(State.RestOfRow());
4134 if (State.PeekNextCharSameRow() ==
':')
4138 State.NextCharSameRow();
4139 State.SkipWhitespaceSameRow(3);
4144 Positions.
Add(State.CurrentPosition);
4145 Rows.
Add(State.RestOfRow());
4149 State.SkipWhitespaceSameRow(4);
4151 Positions.
Add(State.CurrentPosition);
4152 Rows.
Add(State.RestOfRow());
4163 else if (!(this.emojiSource is
null))
4169 State.NextCharSameRow();
4170 ch2 = State.PeekNextCharSameRow();
4173 if (
char.IsLetter(ch2) ||
char.IsDigit(ch2) || ch2 ==
'+')
4175 this.AppendAnyText(
Elements, Text);
4176 State.NextCharSameRow();
4178 ch3 = State.PeekNextCharSameRow();
4179 if (
char.IsLetter(ch3) ||
char.IsDigit(ch3) || ch3 ==
'_' || ch3 ==
'-' || ch3 ==
':')
4186 State.NextCharSameRow();
4188 Text.Append(
new string(
':', LeftLevel - 1));
4190 this.AppendAnyText(
Elements, Text);
4195 State.NextCharSameRow();
4197 Text.Append(
new string(
':', LeftLevel - 1));
4199 this.AppendAnyText(
Elements, Text);
4208 State.NextCharSameRow();
4210 Text.Append(
new string(
':', LeftLevel - 1));
4212 this.AppendAnyText(
Elements, Text);
4218 State.NextCharSameRow();
4220 Text.Append(
new string(
':', LeftLevel - 1));
4222 this.AppendAnyText(
Elements, Text);
4228 State.NextCharSameRow();
4230 Text.Append(
new string(
':', LeftLevel - 1));
4232 this.AppendAnyText(
Elements, Text);
4246 while (
char.IsLetter(ch3 = State.PeekNextCharSameRow()) ||
char.IsDigit(ch3) || ch3 ==
'_' || ch3 ==
'-')
4248 State.NextCharSameRow();
4256 while (ch3 ==
':' && RightLevel < LeftLevel)
4259 State.NextCharSameRow();
4260 ch3 = State.PeekNextCharSameRow();
4263 Title = Text.ToString().ToLower();
4267 if (LeftLevel > RightLevel)
4275 Text.Insert(0,
new string(
':', LeftLevel));
4276 Text.Append(
new string(
':', RightLevel));
4280 Text.Insert(0,
new string(
':', LeftLevel));
4285 Text.Append(
new string(
':', LeftLevel - 1));
4290 State.NextCharSameRow();
4292 switch (State.PeekNextCharSameRow())
4295 State.NextCharSameRow();
4296 this.AppendAnyText(
Elements, Text);
4301 State.NextCharSameRow();
4302 this.AppendAnyText(
Elements, Text);
4307 State.NextCharSameRow();
4308 if ((ch3 = State.PeekNextCharSameRow()) ==
')')
4310 State.NextCharSameRow();
4311 this.AppendAnyText(
Elements, Text);
4314 else if (ch3 ==
'(')
4316 State.NextCharSameRow();
4317 this.AppendAnyText(
Elements, Text);
4331 State.NextCharSameRow();
4333 switch (State.PeekNextCharSameRow())
4337 State.NextCharSameRow();
4338 this.AppendAnyText(
Elements, Text);
4344 State.NextCharSameRow();
4345 this.AppendAnyText(
Elements, Text);
4350 State.NextCharSameRow();
4351 this.AppendAnyText(
Elements, Text);
4356 State.NextCharSameRow();
4357 this.AppendAnyText(
Elements, Text);
4365 State.NextCharSameRow();
4366 this.AppendAnyText(
Elements, Text);
4375 State.NextCharSameRow();
4376 this.AppendAnyText(
Elements, Text);
4382 State.NextCharSameRow();
4383 this.AppendAnyText(
Elements, Text);
4390 State.NextCharSameRow();
4391 this.AppendAnyText(
Elements, Text);
4396 State.NextCharSameRow();
4397 if ((ch3 = State.PeekNextCharSameRow()) ==
')')
4399 State.NextCharSameRow();
4400 this.AppendAnyText(
Elements, Text);
4403 else if (ch3 ==
'(')
4405 State.NextCharSameRow();
4406 this.AppendAnyText(
Elements, Text);
4414 State.NextCharSameRow();
4415 if (State.PeekNextCharSameRow() ==
':')
4417 State.NextCharSameRow();
4418 this.AppendAnyText(
Elements, Text);
4433 State.NextCharSameRow();
4434 this.AppendAnyText(
Elements, Text);
4440 State.NextCharSameRow();
4441 this.AppendAnyText(
Elements, Text);
4446 State.NextCharSameRow();
4447 this.AppendAnyText(
Elements, Text);
4453 State.NextCharSameRow();
4454 this.AppendAnyText(
Elements, Text);
4459 State.NextCharSameRow();
4460 this.AppendAnyText(
Elements, Text);
4465 State.NextCharSameRow();
4466 this.AppendAnyText(
Elements, Text);
4471 State.NextCharSameRow();
4472 this.AppendAnyText(
Elements, Text);
4477 State.NextCharSameRow();
4478 if (State.PeekNextCharSameRow() ==
'*')
4480 State.NextCharSameRow();
4481 this.AppendAnyText(
Elements, Text);
4499 if (!(this.emojiSource is
null))
4501 switch (State.PeekNextCharSameRow())
4506 State.NextCharSameRow();
4507 this.AppendAnyText(
Elements, Text);
4513 State.NextCharSameRow();
4514 this.AppendAnyText(
Elements, Text);
4519 State.NextCharSameRow();
4520 switch (State.PeekNextCharSameRow())
4524 State.NextCharSameRow();
4525 this.AppendAnyText(
Elements, Text);
4531 State.NextCharSameRow();
4532 this.AppendAnyText(
Elements, Text);
4543 State.NextCharSameRow();
4544 if (State.PeekNextCharSameRow() ==
')')
4546 State.NextCharSameRow();
4547 this.AppendAnyText(
Elements, Text);
4565 if (!(this.emojiSource is
null) && (
char.IsPunctuation(PrevChar) ||
char.IsWhiteSpace(PrevChar)))
4567 switch (State.PeekNextCharSameRow())
4570 State.BackupState();
4571 State.NextCharSameRow();
4572 switch (State.PeekNextCharSameRow())
4579 State.DiscardBackup();
4580 State.NextCharSameRow();
4581 this.AppendAnyText(
Elements, Text);
4586 State.DiscardBackup();
4587 State.NextCharSameRow();
4588 this.AppendAnyText(
Elements, Text);
4593 State.RestoreState();
4600 State.NextCharSameRow();
4601 this.AppendAnyText(
Elements, Text);
4615 if (!(this.emojiSource is
null) && (
char.IsPunctuation(PrevChar) ||
char.IsWhiteSpace(PrevChar)))
4617 switch (State.PeekNextCharSameRow())
4620 State.BackupState();
4621 State.NextCharSameRow();
4622 switch (State.PeekNextCharSameRow())
4626 State.DiscardBackup();
4627 State.NextCharSameRow();
4628 this.AppendAnyText(
Elements, Text);
4633 State.RestoreState();
4640 State.NextCharSameRow();
4641 this.AppendAnyText(
Elements, Text);
4655 if (!(this.emojiSource is
null) && (
char.IsPunctuation(PrevChar) ||
char.IsWhiteSpace(PrevChar)) && State.PeekNextCharSameRow() ==
':')
4657 State.NextCharSameRow();
4658 this.AppendAnyText(
Elements, Text);
4666 if (!(this.emojiSource is
null) && (
char.IsPunctuation(PrevChar) ||
char.IsWhiteSpace(PrevChar)))
4668 switch (State.PeekNextCharSameRow())
4671 State.BackupState();
4672 State.NextCharSameRow();
4673 switch (State.NextCharSameRow())
4677 State.DiscardBackup();
4678 this.AppendAnyText(
Elements, Text);
4683 if ((ch3 = State.NextCharSameRow()) ==
')' || ch3 ==
'3')
4685 State.DiscardBackup();
4686 this.AppendAnyText(
Elements, Text);
4691 State.RestoreState();
4697 State.RestoreState();
4704 State.BackupState();
4705 State.NextCharSameRow();
4706 if (State.NextCharSameRow() ==
'-')
4708 if (State.NextCharSameRow() ==
')')
4710 State.DiscardBackup();
4711 this.AppendAnyText(
Elements, Text);
4717 State.RestoreState();
4722 State.BackupState();
4723 State.NextCharSameRow();
4724 if (State.PeekNextCharSameRow() ==
')')
4726 State.NextCharSameRow();
4727 State.DiscardBackup();
4728 this.AppendAnyText(
Elements, Text);
4733 State.RestoreState();
4739 State.BackupState();
4740 State.NextCharSameRow();
4741 if (State.PeekNextCharSameRow() ==
'O')
4743 State.NextCharSameRow();
4744 State.DiscardBackup();
4745 this.AppendAnyText(
Elements, Text);
4750 State.RestoreState();
4765 if (
char.IsWhiteSpace(PrevChar) && State.PeekNextCharSameRow() ==
't')
4767 FirstCharOnLine = State.IsFirstCharOnLine;
4769 chs = State.PeekNextChars(7);
4770 if (chs[1] ==
't' && chs[2] ==
'p' &&
4771 ((chs[3] ==
':' && chs[4] ==
'/' && chs[5] ==
'/') ||
4772 (chs[3] ==
's' && chs[4] ==
':' && chs[5] ==
'/' && chs[6] ==
'/')))
4774 this.AppendAnyText(
Elements, Text);
4786 Text.Append(State.NextChar());
4790 while ((ch2 = State.PeekNextCharSameRow()) >
' ' && ch2 != 160)
4796 Url = Text.ToString();
4799 if (FirstCharOnLine && State.PeekNextNonWhitespaceCharSameRow(
false) == 0)
4814 if (!(this.settings?.Progress is
null))
4835 switch (ch2 = State.PeekNextCharSameRow())
4865 State.NextCharSameRow();
4870 if (!(this.emojiSource is
null))
4872 State.BackupState();
4873 State.NextCharSameRow();
4874 if (State.PeekNextCharSameRow() ==
'/')
4876 State.DiscardBackup();
4877 State.NextCharSameRow();
4878 this.AppendAnyText(
Elements, Text);
4883 State.RestoreState();
4902 PrevChar = State.LastCharacter;
4905 this.AppendAnyText(
Elements, Text);
4907 return (ch == TerminationCharacter) || AcceptIncomplete;
4910 private static bool IsLeftQuote(
char PrevChar,
char NextChar)
4912 bool Left = (PrevChar <=
' ' || PrevChar == 160 ||
char.IsPunctuation(PrevChar) ||
char.IsSeparator(PrevChar));
4913 bool Right = (NextChar <=
' ' || NextChar == 160 ||
char.IsPunctuation(NextChar) ||
char.IsSeparator(NextChar));
4917 if (
char.IsSeparator(PrevChar))
4919 else if (
char.IsSeparator(NextChar))
4921 else if (PrevChar ==
')' || PrevChar ==
']' || PrevChar ==
'}')
4923 else if (NextChar ==
'(' || NextChar ==
'[' || NextChar ==
'[')
4932 private static void ParseWidthHeight(BlockParseState State, out
int? Width, out
int? Height)
4937 char ch = State.PeekNextNonWhitespaceCharSameRow(
true);
4938 if (ch >=
'0' && ch <=
'9')
4940 StringBuilder Text =
new StringBuilder();
4943 State.NextNonWhitespaceCharSameRow();
4945 ch = State.PeekNextCharSameRow();
4946 while (ch >=
'0' && ch <=
'9')
4949 State.NextCharSameRow();
4950 ch = State.PeekNextCharSameRow();
4953 if (
int.TryParse(Text.ToString(), out
int i))
4958 ch = State.PeekNextNonWhitespaceCharSameRow(
true);
4959 if (ch >=
'0' && ch <=
'9')
4962 State.NextNonWhitespaceCharSameRow();
4964 ch = State.PeekNextCharSameRow();
4965 while (ch >=
'0' && ch <=
'9')
4968 State.NextCharSameRow();
4969 ch = State.PeekNextCharSameRow();
4972 if (
int.TryParse(Text.ToString(), out i))
4981 if (Text.Length > 0)
4983 string s = Text.ToString();
4997 internal static bool IsPrefixedByNumber(
string s, out
int Numeral)
4999 int i, c = s.Length;
5003 while (i < c &&
char.IsDigit(s[i]))
5012 if (!
int.TryParse(s.Substring(0, i), out Numeral) || i == c || s[i] !=
'.')
5016 if (i < c && (ch = s[i]) >
' ' && ch != 160)
5022 internal static bool IsPrefixedBy(
string s,
string Prefix,
bool MustHaveWhiteSpaceAfter)
5027 if (!s.StartsWith(Prefix))
5030 if (MustHaveWhiteSpaceAfter)
5032 if (s.Length == (i =
Prefix.Length))
5035 return (ch = s[i]) <=
' ' || ch == 160;
5041 private static bool IsPrefixedBy(
string s,
char ch, out
int Count,
bool MustHaveWhiteSpaceAfter)
5046 while (Count < c && s[Count] == ch)
5052 if (MustHaveWhiteSpaceAfter)
5054 if (s.Length == Count)
5057 return (ch = s[Count]) <=
' ' || ch == 160;
5063 internal static bool IsSuffixedBy(
string s,
string Suffix)
5065 return s.EndsWith(Suffix);
5082 private static bool IsUnderline(
string s,
char ch,
bool AllowSpaces,
bool OnlyOneSpace)
5084 int i, c = s.Length;
5085 bool LastSpace =
true;
5089 for (i = 0; i < c; i++)
5097 else if (ch2 ==
' ' || ch2 == 160)
5099 if (OnlyOneSpace && (!AllowSpaces || LastSpace))
5116 int FirstLineIndent = 0;
5122 bool InBlock =
false;
5124 bool NonWhitespaceInRow =
false;
5125 bool StartsWithHashSigns =
false;
5126 bool IsHeader =
false;
5127 bool HasRows =
false;
5131 for (Pos = 0; Pos < Len; Pos++)
5139 if (InRow && NonWhitespaceInRow)
5142 LineIndent < FirstLineIndent &&
5145 Blocks.
Add(
new Block(Rows.
ToArray(), Positions.
ToArray(), FirstLineIndent / 4));
5148 FirstLineIndent = LineIndent;
5151 Positions.
Add(RowStart);
5156 if (IsHeader && Rows.
Count == 1)
5158 Blocks.
Add(
new Block(Rows.
ToArray(), Positions.
ToArray(), FirstLineIndent / 4));
5163 FirstLineIndent = 0;
5168 Blocks.
Add(
new Block(Rows.
ToArray(), Positions.
ToArray(), FirstLineIndent / 4));
5174 FirstLineIndent = 0;
5178 FirstLineIndent = 0;
5181 NonWhitespaceInRow =
false;
5182 StartsWithHashSigns =
false;
5185 else if (ch <=
' ' || ch == 160)
5193 if (StartsWithHashSigns)
5198 if (LineIndent >= FirstLineIndent)
5201 RowStart = RowEnd = Pos;
5206 else if (ch ==
' ' || ch == 160)
5210 else if (ch ==
'\t')
5211 FirstLineIndent += 4;
5212 else if (ch ==
' ' || ch == 160)
5215 StartsWithHashSigns =
false;
5226 StartsWithHashSigns =
true;
5229 StartsWithHashSigns =
false;
5232 NonWhitespaceInRow =
true;
5238 if (InRow && NonWhitespaceInRow)
5240 Positions.
Add(RowStart);
5245 Blocks.
Add(
new Block(Rows.
ToArray(), Positions.
ToArray(), FirstLineIndent / 4));
5251 private static bool IsListPrefix(
string MarkdownText,
int Pos)
5257 if (ch ==
'*' || ch ==
'+' || ch ==
'-')
5258 ExpectPeriod =
false;
5260 ExpectPeriod =
true;
5263 ExpectPeriod =
false;
5268 if (ch !=
' ' && ch !=
'x' && ch !=
'X')
5278 else if (ch >=
'0' && ch <=
'9')
5280 ExpectPeriod =
true;
5282 while (Pos < c && (ch =
MarkdownText[Pos]) >=
'0' && ch <=
'9')
5303 return ch <=
' ' || ch == 160;
5312 if (this.metaData.TryGetValue(
"MASTER", out KeyValuePair<string, bool>[]
Master) &&
Master.Length == 1)
5314 await this.LoadMasterIfNotLoaded(
Master[0].Key);
5315 this.master.ClearFootnoteReferences();
5320 this.ClearFootnoteReferences();
5330 private void ClearFootnoteReferences()
5332 if (!(this.footnotes is
null))
5335 Footnote.Referenced =
false;
5344 private async Task LoadMasterIfNotLoaded(
string MasterMetaValue)
5346 if (this.master is
null)
5350 if (!
string.IsNullOrEmpty(this.url) &&
5351 Uri.TryCreate(
this.url, UriKind.Absolute, out Uri ParsedUri) &&
5352 Uri.TryCreate(ParsedUri, MasterMetaValue, out Uri MasterUri) &&
5353 !(
this.settings.ResourceMap is
null) &&
5354 this.settings.ResourceMap.TryGetFileName(MasterUri.AbsoluteUri,
false, out
string s))
5358 else if (!
string.IsNullOrEmpty(this.fileName) &&
5359 File.Exists(s =
this.settings.GetFileName(
this.fileName, MasterMetaValue)))
5363 else if (!
string.IsNullOrEmpty(this.resourceName))
5365 FileName = Path.Combine(this.resourceName.Replace(
'/', Path.DirectorySeparatorChar), MasterMetaValue);
5366 if (!(this.settings.ResourceMap is
null) &&
this.settings.ResourceMap.TryGetFileName(
FileName,
false, out s))
5373 this.settings?.Progress?.DependencyTimestamp(File.GetLastWriteTimeUtc(
FileName));
5377 this.master.syntaxHighlighting |= this.syntaxHighlighting;
5379 if (this.master.metaData.ContainsKey(
"MASTER"))
5381 throw new GenericException(
"Master documents are not allowed to be embedded in other master documents.",
5385 CopyMetaDataTags(
this, this.master,
true);
5387 this.master.detail =
this;
5393 if (UpdateMasterPaths && !
string.IsNullOrEmpty(Details.fileName) && !
string.IsNullOrEmpty(
Master.fileName))
5395 string DetailsFileName = Path.GetFullPath(Details.fileName);
5396 string MasterFileName = Path.GetFullPath(
Master.fileName);
5397 string DetailsFolder = Path.GetDirectoryName(DetailsFileName);
5398 string MasterFolder = Path.GetDirectoryName(MasterFileName);
5400 if (DetailsFolder != MasterFolder)
5402 string Prefix =
null;
5404 foreach (KeyValuePair<
string, KeyValuePair<string, bool>[]> Meta
in Master.metaData)
5422 int i, j, k, l, c, d;
5424 for (k = 0, l = Meta.Value.Length; k < l; k++)
5426 string s = Meta.Value[k].Key;
5427 if (
string.IsNullOrEmpty(s))
5430 if (s[0] == Path.DirectorySeparatorChar || s[0] ==
'/')
5435 string[] DetailsParts = DetailsFolder.Split(Path.DirectorySeparatorChar);
5436 string[] MasterParts = MasterFolder.Split(Path.DirectorySeparatorChar);
5439 c = DetailsParts.Length;
5440 d = MasterParts.Length;
5442 while (i < c && i < d &&
string.
Compare(DetailsParts[i], MasterParts[i],
true) == 0)
5445 StringBuilder sb =
new StringBuilder();
5454 sb.Append(MasterParts[i++]);
5458 Prefix = sb.ToString();
5461 Meta.Value[k] =
new KeyValuePair<string, bool>(Prefix + s, Meta.Value[k].Value);
5469 foreach (KeyValuePair<
string, KeyValuePair<string, bool>[]> Meta
in Details.metaData)
5471 if (
Master.metaData.TryGetValue(Meta.Key, out KeyValuePair<string, bool>[] Meta0))
5472 Master.metaData[Meta.Key] = Meta0.Join(Meta.Value);
5474 Master.metaData[Meta.Key] = Meta.Value;
5481 internal bool NeedsToDisplayFootnotes
5485 if (this.footnotes is
null)
5507 bool IsRelative = Url.IndexOf(
':') < 0;
5509 if (Url.StartsWith(
"httpx:", StringComparison.OrdinalIgnoreCase) && !
string.IsNullOrEmpty(
this.settings.HttpxProxy))
5511 if (!
string.IsNullOrEmpty(this.settings.LocalHttpxResourcePath) &&
5512 Url.StartsWith(
this.settings.LocalHttpxResourcePath, StringComparison.OrdinalIgnoreCase))
5514 Url = Url.Substring(this.settings.LocalHttpxResourcePath.Length);
5515 if (!Url.StartsWith(
"/") &&
this.settings.LocalHttpxResourcePath.EndsWith(
"/"))
5522 Url = this.settings.HttpxProxy.Replace(
"%URL%", Url);
5523 IsRelative = this.settings.HttpxProxy.IndexOf(
':') < 0;
5527 if (IsRelative && !
string.IsNullOrEmpty(
URL))
5529 if (Uri.TryCreate(
new Uri(
URL), Url, out Uri AbsoluteUri))
5530 Url = AbsoluteUri.ToString();
5553 StringBuilder Output =
new StringBuilder();
5555 return Output.ToString();
5577 PortableSyntax = PortableSyntax
5590 StringBuilder Output =
new StringBuilder();
5592 return Output.ToString();
5611 StringBuilder Output =
new StringBuilder();
5613 return Output.ToString();
5635 StringBuilder Output =
new StringBuilder();
5637 return Output.ToString();
5659 if (this.references.TryGetValue(Label.ToLower(), out
Multimedia Result))
5665 private static readonly
char[] whiteSpace =
new char[]
5667 (char)1, (
char)2, (char)3, (
char)4, (char)5, (
char)6, (char)7, (
char)8, (char)9,(
char)10,
5668 (char)11, (
char)12, (char)13, (
char)14, (char)15, (
char)16, (char)17, (
char)18, (char)19,(
char)20,
5669 (char)21, (
char)22, (char)23, (
char)24, (char)25, (
char)26, (char)27, (
char)28, (char)29,(
char)30,
5686 return this.metaData.TryGetValue(Key.ToUpper(), out Value);
5696 if (this.metaData.TryGetValue(Key, out KeyValuePair<string, bool>[] Records))
5700 Values.
Add(
new KeyValuePair<string, bool>(Value.Trim(), Value.EndsWith(
" ")));
5703 this.metaData[Key] =
new KeyValuePair<string, bool>[] {
new KeyValuePair<string, bool>(Value.Trim(), Value.EndsWith(
" ")) };
5713 if (!this.metaData.TryGetValue(Key.ToUpper(), out KeyValuePair<string, bool>[] Value))
5714 return Array.Empty<
string>();
5716 int i, c = Value.Length;
5717 string[] Result =
new string[c];
5719 for (i = 0; i < c; i++)
5720 Result[i] = Value[i].Key;
5732 string[] Keys =
new string[this.metaData.Count];
5733 this.metaData.Keys.CopyTo(Keys, 0);
5741 public IEnumerable<KeyValuePair<string, KeyValuePair<string, bool>[]>>
MetaData => this.metaData;
5746 public IEnumerable<KeyValuePair<string, Multimedia>>
References => this.references;
5763 private string[] Merge(
string[] L1,
string[] L2)
5767 if ((c1 = L1.Length) == 0)
5769 else if ((c2 = L2.Length) == 0)
5772 string[] L =
new string[c1 + c2];
5774 Array.Copy(L1, 0, L, 0, c1);
5775 Array.Copy(L2, 0, L, c1, c2);
5875 if (this.footnoteNumberByKey is
null)
5881 return this.footnoteNumberByKey.TryGetValue(Key, out Number);
5892 if (this.footnotes is
null)
5898 return this.footnotes.TryGetValue(Key, out
Footnote);
5909 if (this.footnoteOrder is
null)
5910 return Array.Empty<
string>();
5912 return this.footnoteOrder.
ToArray();
5928 return Functions.MarkdownEncode.EscapeText(s);
5941 get => this.fileName;
5942 set => this.fileName = value;
5951 get => this.resourceName;
5952 set => this.resourceName = value;
5961 set => this.url = value;
5970 set => this.master = value;
5980 if (!(this.detail is
null))
5983 if (this.master is
null)
5992 set => this.detail = value;
6008 public bool IsDynamic => this.isDynamic || (this.master?.isDynamic ??
false);
6016 set => this.tag = value;
6026 if (!this.allowScriptTag.HasValue)
6028 this.allowScriptTag = this.metaData.TryGetValue(
"ALLOWSCRIPTTAG", out KeyValuePair<string, bool>[] Value) &&
6034 return this.allowScriptTag.Value;
6049 while (!(Loop is
null))
6051 for (i = Loop.
Start, c = Loop.
Pos; i < c; i++)
6053 if (!Loop[i].
ForEach(Callback, State))
6060 if (!(this.references is
null))
6062 foreach (
Multimedia E
in this.references.Values)
6064 if (!E.
ForEach(Callback, State))
6069 if (!(this.footnotes is
null))
6071 foreach (
Footnote E
in this.footnotes.Values)
6073 if (!E.
ForEach(Callback, State))
6087 return this.
FindLinks(
true,
true,
true);
6097 public string[]
FindLinks(
bool IncludeAutomaticLinks,
bool IncludeLinks,
bool IncludeMultimedia)
6099 Dictionary<string, bool> Links =
new Dictionary<string, bool>();
6105 if (IncludeAutomaticLinks)
6115 if (IncludeMultimedia)
6118 Links[Item.
Url] =
true;
6125 string[] Result =
new string[Links.Count];
6126 Links.Keys.CopyTo(Result, 0);
6136 SortedDictionary<string, bool> Tags =
new SortedDictionary<string, bool>();
6141 Tags[
Tag.Tag] =
true;
6146 string[] Result =
new string[Tags.Count];
6147 Tags.Keys.CopyTo(Result, 0);
6164 IEnumerator IEnumerable.GetEnumerator()
6178 return New.
Compare(Old, KeepUnchanged);
6217 Result.markdownText =
null;
6223 if (ContainsEditableText(
Elements))
6242 while (!(Loop is
null))
6244 for (i = Loop.
Start, c = Loop.
Pos; i < c; i++)
6249 Result.
AddRange(EditableText.Atomize());
6265 while (!(Loop is
null))
6267 for (i = Loop.
Start, c = Loop.
Pos; i < c; i++)
6287 int i, c =
Script.Steps.Length;
6289 if (Reassemble1 || Reassemble2)
6292 StringBuilder sb =
new StringBuilder();
6294 for (i = 0; i < c; i++)
6315 Type LastAtomType =
null;
6316 Atom LastAtom =
null;
6327 AtomType =
Atom.GetType();
6328 if (AtomType != LastAtomType)
6330 if (!(LastAtom is
null))
6337 LastAtomType = AtomType;
6344 if (!(LastAtom is
null))
6349 LastAtomType =
null;
6356 if (!(LastAtom is
null))
6362 Step.Symbols = Reassembled.
ToArray();
6363 Reassembled.
Clear();
6367 for (i = 0; i < c; i++)
6388 for (j = 0; j < d; j++)
6405 KeepUnchanged || d > 1, Document);
6407 Result.
Add(Children1.Create(Diff, Document));
6416 KeepUnchanged || d > 1, Document);
6418 Result.
Add(Child1.Create(GrandChildren1.Create(Diff, Document), Document));
6439 if (Symbols[0].IsBlockElement)
6467 int i, c = E1.Length;
6473 for (i = 0; i < c; i++)
6475 if (!(e = E1[i]).IsBlockElement)
6493 lock (this.asyncTasks)
6495 this.asyncTasks.Add(
new KeyValuePair<AsyncMarkdownProcessing, object>(Callback, State));
6502 public IEnumerable<KeyValuePair<AsyncMarkdownProcessing, object>>
AsyncTasks
6506 lock (this.asyncTasks)
6508 return this.asyncTasks.ToArray();
6518 KeyValuePair<AsyncMarkdownProcessing, object>[] Tasks;
6520 lock (this.asyncTasks)
6522 if (this.asyncTasks.Count == 0)
6525 Tasks = this.asyncTasks.ToArray();
6526 this.asyncTasks.Clear();
6529 Task.Run(async () =>
6531 foreach (KeyValuePair<AsyncMarkdownProcessing, object> P
in Tasks)
6535 await P.Key(P.Value);
6537 catch (Exception ex)
6556 if (Visualizer is
null)
6561 catch (Exception ex)
6578 Element.IncrementStatistics(Result);
6582 Result.MailHyperlinks = Result.IntMailHyperlinks?.
ToArray();
6583 Result.UrlHyperlinks = Result.IntUrlHyperlinks?.
ToArray();
6585 this.GenerateStatDictionary(Result.IntMultimediaPerContentCategory,
6586 out Dictionary<
string,
string[]> AsArrays, out Dictionary<string, int> AsCounts);
6588 Result.MultimediaPerContentCategory = AsArrays;
6589 Result.NrMultimediaPerContentCategory = AsCounts;
6591 this.GenerateStatDictionary(Result.IntMultimediaPerContentType, out AsArrays, out AsCounts);
6592 Result.MultimediaPerContentType = AsArrays;
6593 Result.NrMultimediaPerContentType = AsCounts;
6595 this.GenerateStatDictionary(Result.IntMultimediaPerExtension, out AsArrays, out AsCounts);
6596 Result.MultimediaPerExtension = AsArrays;
6597 Result.NrMultimediaPerExtension = AsCounts;
6602 private void GenerateStatDictionary(Dictionary<
string,
ChunkedList<string>> Temp, out Dictionary<
string,
string[]> AsArrays, out Dictionary<string, int> AsCounts)
6611 AsArrays =
new Dictionary<string, string[]>();
6612 AsCounts =
new Dictionary<string, int>();
6616 AsArrays[P.Key] = P.Value.ToArray();
6617 AsCounts[P.Key] = P.Value.Count;
6639 if (SingleRow && Rows.Length == 1)
6640 return Rows[0].Trim();
6642 StringBuilder sb =
new StringBuilder();
6644 foreach (
string Row
in Rows)
6647 sb.Append(Row.Trim());
6652 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
Helps with common JSON-related tasks.
static string IndentString(int NrTabs)
Gets an indentation string consisting of a number of tab characters. Strings are caches and reused to...
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.
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.
static async Task< KeyValuePair< string, bool > > Preprocess(string Markdown, MarkdownSettings Settings, string FileName, params Type[] TransparentExceptionTypes)
Preprocesses 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.
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< 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.
ChunkedList< MarkdownElement > Elements
Markdown elements making up the document.
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.
object ScriptContext
Context object to be passed to script expressions. This can be used to ensure context-specific functi...
AuthorizeExpression AuthorizeExpression
Optional method to call to authorize execution of script expressions.
ICodecProgress Progress
Optional progress reporting of encoding/decoding. Can be null.
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.
static IXmlVisualizer GetXmlVisualizerHandler(XmlDocument Xml)
Gets the best XML Visualizer for a given XML document.
Represents a definition list in a markdown document.
override void AddChild(MarkdownElement NewChild)
Adds a child 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 AddChild(MarkdownElement NewChild)
Adds a child to the element.
override void AddChildren(ChunkedList< 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.
virtual void AddChildren(ChunkedList< MarkdownElement > NewChildren)
Adds children to the element.
override ChunkedList< MarkdownElement > Children
Any children of the element.
virtual void AddChild(MarkdownElement NewChild)
Adds a child to the element.
override bool ForEach(MarkdownElementHandler Callback, object State)
Loops through all child-elements for 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 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 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.
async Task< bool > Render(ChunkedList< MarkdownElement > Elements)
Renders a collection of elements.
void Clear()
Clears the underlying StringBuilder.
override string ToString()
Returns the renderer output.
Renders plain text from a Markdown document.
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.
Node referencing a chunk in a ChunkedList<T>
override string ToString()
String representation of chunk.
ChunkNode< T > Next
Next chunk
int Pos
Index after the last element in chunk.
int Start
Index of first element in chunk.
A chunked list is a linked list of chunks of objects of type T .
void Clear()
Clears the collection.
IEnumerator< T > GetEnumerator()
Returns an enumerator for the collection.
void AddFirstItem(T Value)
Adds a new item first in the collection.
T LastItem
Last item in the collection.
void AddRange(IEnumerable< T > Collection)
Adds a range of elements (last) to the list.
ChunkNode< T > FirstChunk
First chunk
bool HasFirstItem
If there is a first item in the collection
bool HasLastItem
If there is a last item in the collection
int IndexOf(T Item)
Determines the index of a specific item
T FirstItem
First item in the collection.
int Count
Number of elements in collection.
void AddRangeFirst(IEnumerable< T > Collection)
Adds a range of elements first to the list.
void Add(T Item)
Adds an item to the collection.
T[] ToArray()
Returns an array containing all elements of the collection.
static async Task< string > ReadAllTextAsync(string FileName)
Reads a text file asynchronously.
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.
static bool IsNullOrVoid(object Result)
Checks if a result object value is equal to null or void (i.e. its type equal to System....
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.
ValuePrinter Printer
Delegate that converts values to strings for (implicit) printing. Default is null,...
Interface for Emoji sources. Emoji sources provide emojis to content providers.
Interface for reporting progress about an encoding or decoding.
Task HeaderProcessed()
Called when the header has been processed.
Task EarlyHint(string Resource, string Relation, params KeyValuePair< string, string >[] AdditionalParameters)
Reports an early hint of a resource the recipient may need to process, in order to be able to process...
Task BodyProcessed()
Called when the body has been processed.
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.