Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
MarkdownRenderer.cs
1using SkiaSharp;
2using System;
4using System.Text;
5using System.Threading.Tasks;
6using System.Xml;
12using Waher.Events;
14using Waher.Script;
19
21{
26 {
27 private bool portableSyntax = true;
28
33 : base()
34 {
35 }
36
41 public MarkdownRenderer(StringBuilder Output)
42 : base(Output)
43 {
44 }
45
51 : base(Document)
52 {
53 }
54
61 : base(Output, Document)
62 {
63 }
64
69 public bool PortableSyntax
70 {
71 get => this.portableSyntax;
72 set => this.portableSyntax = value;
73 }
74
78 public override async Task RenderFootnotes()
79 {
80 if (!(this.Document?.FootnoteOrder is null))
81 {
83 {
84 foreach (string Key in this.Document.FootnoteOrder)
85 {
86 if (!Guid.TryParse(Key, out _) &&
87 (this.Document?.TryGetFootnote(Key, out Footnote Note) ?? false) &&
88 Note.Referenced)
89 {
90 this.Output.AppendLine();
91 this.Output.AppendLine();
92 this.Output.Append("[^");
93 this.Output.Append(Key);
94 this.Output.Append("]:");
95
96 await Note.Render(Renderer);
97
98 string s = Renderer.ToString();
100
101 foreach (string Row in s.Replace("\r\n", "\n").Replace('\r', '\n').Split('\n'))
102 {
103 this.Output.Append('\t');
104 this.Output.AppendLine(Row);
105 }
106 }
107 }
108 }
109 }
110 }
111
112 #region Span Elements
113
118 public override async Task Render(Abbreviation Element)
119 {
120 this.Output.Append('[');
121 await this.RenderChildren(Element);
122 this.Output.Append("](abbr:");
123 this.Output.Append(Element.Description);
124 this.Output.Append(')');
125 }
126
131 public override Task Render(AutomaticLinkMail Element)
132 {
133 this.Output.Append('<');
134 this.Output.Append(Element.EMail);
135 this.Output.Append('>');
136
137 return Task.CompletedTask;
138 }
139
144 public override Task Render(AutomaticLinkUrl Element)
145 {
146 this.Output.Append('<');
147 this.Output.Append(Element.URL);
148 this.Output.Append('>');
149
150 return Task.CompletedTask;
151 }
152
157 public override async Task Render(Delete Element)
158 {
159 this.Output.Append("~~");
160 await this.RenderChildren(Element);
161 this.Output.Append("~~");
162 }
163
168 public override Task Render(DetailsReference Element)
169 {
170 if (!(this.Document.Detail is null))
171 return this.RenderDocument(this.Document.Detail, true);
172 else
173 return this.Render((MetaReference)Element);
174 }
175
180 public override Task Render(EmojiReference Element)
181 {
182 this.Output.Append(Element.Delimiter);
183 this.Output.Append(Element.Emoji.ShortName);
184 this.Output.Append(Element.Delimiter);
185
186 return Task.CompletedTask;
187 }
188
193 public override async Task Render(Emphasize Element)
194 {
195 this.Output.Append('*');
196 await this.RenderChildren(Element);
197 this.Output.Append('*');
198 }
199
204 public override async Task Render(FootnoteReference Element)
205 {
206 this.Output.Append("[^");
207
208 if (!(this.Document?.TryGetFootnote(Element.Key, out Footnote Footnote) ?? false))
209 Footnote = null;
210
211 if (Guid.TryParse(Element.Key, out _) && !(Footnote is null))
212 {
214 {
215 await Renderer.Render(Footnote);
216
217 this.Output.Append(Renderer.ToString().TrimEnd());
218 }
219 }
220 else
221 {
222 this.Output.Append(Element.Key);
223
224 if (!(Footnote is null))
225 Footnote.Referenced = true;
226 }
227
228 this.Output.Append(']');
229 }
230
235 public override Task Render(HashTag Element)
236 {
237 this.Output.Append('#');
238 this.Output.Append(Element.Tag);
239
240 return Task.CompletedTask;
241 }
242
247 public override Task Render(HtmlEntity Element)
248 {
249 switch (Element.Entity)
250 {
251 case "quot":
252 case "amp":
253 case "apos":
254 case "lt":
255 case "gt":
256 case "nbsp": // Has syntactic significance when parsing HTML or Markdown
257 this.Output.Append('&');
258 this.Output.Append(Element.Entity);
259 this.Output.Append(';');
260 break;
261
262 case "QUOT":
263 case "AMP":
264 case "LT":
265 case "GT":
266 this.Output.Append('&');
267 this.Output.Append(Element.Entity.ToLower());
268 this.Output.Append(';');
269 break;
270
271 default:
272 string s = Html.HtmlEntity.EntityToCharacter(Element.Entity);
273 if (!string.IsNullOrEmpty(s))
274 this.Output.Append(s);
275 break;
276 }
277
278 return Task.CompletedTask;
279 }
280
285 public override Task Render(HtmlEntityUnicode Element)
286 {
287 this.Output.Append("&#");
288 this.Output.Append(Element.Code.ToString());
289 this.Output.Append(';');
290
291 return Task.CompletedTask;
292 }
293
298 public override Task Render(InlineCode Element)
299 {
300 this.Output.Append('`');
301 this.Output.Append(Element.Code);
302 this.Output.Append('`');
303
304 return Task.CompletedTask;
305 }
306
311 public override Task Render(InlineHTML Element)
312 {
313 this.Output.Append(Element.HTML);
314
315 return Task.CompletedTask;
316 }
317
322 public override async Task Render(InlineScript Element)
323 {
324 object Result = await Element.EvaluateExpression();
325
326 await this.RenderObject(Result, Element.AloneInParagraph, Element.Variables);
327 }
328
335 public async Task RenderObject(object Result, bool AloneInParagraph, Variables Variables)
336 {
337 if (Result is null)
338 return;
339
340 if (Result is XmlDocument Xml)
341 Result = await MarkdownDocument.TransformXml(Xml, Variables);
342 else if (Result is IToMatrix ToMatrix)
343 Result = ToMatrix.ToMatrix();
344
345 if (Result is Graph G)
346 {
348 this.Output.AppendLine();
349 }
350 else if (Result is PixelInformation Pixels)
351 {
352 ToMarkdown.PixelsToMarkdown(Pixels, this.Output);
353 this.Output.AppendLine();
354 }
355 else if (Result is SKImage Img)
356 {
358 this.Output.AppendLine();
359 }
360 else if (Result is MarkdownDocument Doc)
361 {
363 {
364 await Renderer.RenderDocument(Doc, true); // Does not call ProcessAsyncTasks()
365 Doc.ProcessAsyncTasks();
366 }
367 }
368 else if (Result is MarkdownContent Markdown)
369 {
370 Doc = await MarkdownDocument.CreateAsync(Markdown.Markdown, Markdown.Settings ?? new MarkdownSettings());
371
373 {
374 await Renderer.RenderDocument(Doc, true); // Does not call ProcessAsyncTasks()
375 Doc.ProcessAsyncTasks();
376 }
377 }
378 else if (Result is Exception ex)
379 {
380 ex = Log.UnnestException(ex);
381
382 this.Output.Append("<font class=\"error\">");
383
384 if (ex is AggregateException ex2)
385 {
386 foreach (Exception ex3 in ex2.InnerExceptions)
387 {
388 this.Output.Append("<p>");
389 this.Output.Append(XML.HtmlValueEncode(ex3.Message));
390 this.Output.AppendLine("</p>");
391 }
392 }
393 else
394 {
395 if (AloneInParagraph)
396 this.Output.Append("<p>");
397
398 this.Output.Append(MarkdownDocument.Encode(ex.Message));
399
400 if (AloneInParagraph)
401 this.Output.Append("</p>");
402 }
403
404 this.Output.Append("</font>");
405 }
406 else if (Result is IMatrix M)
407 {
409 this.Output.AppendLine();
410 }
411 else if (Result is Array A)
412 {
413 foreach (object Item in A)
414 await this.RenderObject(Item, false, Variables);
415 }
416 else
417 {
418 if (AloneInParagraph)
419 this.Output.Append("<p>");
420
421 this.Output.Append(MarkdownDocument.Encode(Result?.ToString() ?? string.Empty));
422
423 if (AloneInParagraph)
424 this.Output.Append("</p>");
425 }
426
427 if (AloneInParagraph)
428 this.Output.AppendLine();
429 }
430
435 public override Task Render(InlineText Element)
436 {
437 this.Output.Append(MarkdownDocument.Encode(Element.Value));
438
439 return Task.CompletedTask;
440 }
441
446 public override async Task Render(Insert Element)
447 {
448 this.Output.Append("__");
449 await this.RenderChildren(Element);
450 this.Output.Append("__");
451 }
452
457 public override Task Render(LineBreak Element)
458 {
459 this.Output.AppendLine(" ");
460
461 return Task.CompletedTask;
462 }
463
468 public override async Task Render(Link Element)
469 {
470 this.Output.Append('[');
471 await this.RenderChildren(Element);
472 this.Output.Append("](");
473 this.Output.Append(Element.Url);
474
475 if (!string.IsNullOrEmpty(Element.Title))
476 {
477 this.Output.Append(" \"");
478 this.Output.Append(Element.Title.Replace("\"", "\\\""));
479 this.Output.Append('"');
480 }
481
482 this.Output.Append(')');
483 }
484
489 public override async Task Render(LinkReference Element)
490 {
491 this.Output.Append('[');
492 await this.RenderChildren(Element);
493 this.Output.Append("][");
494 this.Output.Append(Element.Label);
495 this.Output.Append(']');
496 }
497
502 public override Task Render(MetaReference Element)
503 {
504 bool FirstOnRow = true;
505
506 if (Element.TryGetMetaData(out KeyValuePair<string, bool>[] Values))
507 {
508 foreach (KeyValuePair<string, bool> P in Values)
509 {
510 if (FirstOnRow)
511 FirstOnRow = false;
512 else
513 this.Output.Append(' ');
514
515 this.Output.Append(MarkdownDocument.Encode(P.Key));
516 if (P.Value)
517 {
518 this.Output.AppendLine(" ");
519 FirstOnRow = true;
520 }
521 }
522 }
523
524 return Task.CompletedTask;
525 }
526
531 public override Task Render(Model.SpanElements.Multimedia Element)
532 {
534 if (Renderer is null)
535 return this.DefaultRenderingMultimedia(Element.Items, Element.Children, Element.AloneInParagraph);
536 else
537 return Renderer.RenderMarkdown(this, Element.Items, Element.Children, Element.AloneInParagraph, Element.Document);
538 }
539
546 private async Task DefaultRenderingMultimedia(MultimediaItem[] Items, ChunkedList<MarkdownElement> ChildNodes,
547 bool AloneInParagraph)
548 {
549 bool First = true;
550
551 this.Output.Append("![");
552 await this.Render(ChildNodes);
553 this.Output.Append(']');
554
555 foreach (MultimediaItem Item in Items)
556 {
557 if (First)
558 First = false;
559 else if (AloneInParagraph)
560 {
561 this.Output.AppendLine();
562 this.Output.Append('\t');
563 }
564
565 this.Output.Append('(');
566 this.Output.Append(Item.Url);
567
568 if (!string.IsNullOrEmpty(Item.Title))
569 {
570 this.Output.Append(" \"");
571 this.Output.Append(Item.Title.Replace("\"", "\\\""));
572 this.Output.Append('"');
573 }
574
575 if (Item.Width.HasValue)
576 {
577 this.Output.Append(' ');
578 this.Output.Append(Item.Width.Value.ToString());
579
580 if (Item.Height.HasValue)
581 {
582 this.Output.Append(' ');
583 this.Output.Append(Item.Height.Value.ToString());
584 }
585 }
586
587 this.Output.Append(')');
588 }
589
590 if (AloneInParagraph)
591 {
592 this.Output.AppendLine();
593 this.Output.AppendLine();
594 }
595 }
596
601 public override Task Render(MultimediaReference Element)
602 {
603 Model.SpanElements.Multimedia Multimedia = Element.Document.GetReference(Element.Label);
604
605 if (!(Multimedia is null))
606 {
608 if (Renderer is null)
609 return this.DefaultRenderingMultimedia(Multimedia.Items, Element.Children, Element.AloneInParagraph);
610 else
611 return Renderer.RenderMarkdown(this, Multimedia.Items, Element.Children, Element.AloneInParagraph, Element.Document);
612 }
613
614 return this.RenderChildren(Element);
615 }
616
621 public override async Task Render(StrikeThrough Element)
622 {
623 this.Output.Append('~');
624 await this.RenderChildren(Element);
625 this.Output.Append('~');
626 }
627
632 public override async Task Render(Strong Element)
633 {
634 this.Output.Append("**");
635 await this.RenderChildren(Element);
636 this.Output.Append("**");
637 }
638
643 public override async Task Render(SubScript Element)
644 {
645 this.Output.Append('[');
646 await this.RenderChildren(Element);
647 this.Output.Append(']');
648 }
649
654 public override async Task Render(SuperScript Element)
655 {
656 this.Output.Append("^[");
657 await this.RenderChildren(Element);
658 this.Output.Append(']');
659 }
660
665 public override async Task Render(Underline Element)
666 {
667 this.Output.Append('_');
668 await this.RenderChildren(Element);
669 this.Output.Append('_');
670 }
671
672 #endregion
673
674 #region Indentation
675
681 private Task PrefixedBlock(ChunkedList<MarkdownElement> Children, string Prefix)
682 {
683 return this.PrefixedBlock(Children, Prefix, Prefix);
684 }
685
692 private Task PrefixedBlock(MarkdownElement Child, string PrefixFirstRow, string PrefixNextRows)
693 {
694 return this.PrefixedBlock(new ChunkedList<MarkdownElement>(Child), PrefixFirstRow, PrefixNextRows);
695 }
696
703 private async Task PrefixedBlock(ChunkedList<MarkdownElement> Children, string PrefixFirstRow, string PrefixNextRows)
704 {
706 {
707 await Renderer.Render(Children);
708
709 string s = Renderer.ToString().Replace("\r\n", "\n").Replace('\r', '\n');
710 string[] Rows = s.Split('\n');
711 int i, c = Rows.Length;
712
713 if (c > 0 && string.IsNullOrEmpty(Rows[c - 1]))
714 c--;
715
716 for (i = 0; i < c; i++)
717 {
718 this.Output.Append(PrefixFirstRow);
719 this.Output.AppendLine(Rows[i]);
720 PrefixFirstRow = PrefixNextRows;
721 }
722 }
723 }
724
730 private Task SuffixedBlock(ChunkedList<MarkdownElement> Children, string Suffix)
731 {
732 return this.SuffixedBlock(Children, Suffix, Suffix);
733 }
734
741 private async Task SuffixedBlock(ChunkedList<MarkdownElement> Children, string SuffixFirstRow, string SuffixNextRows)
742 {
744 {
745 await Renderer.Render(Children);
746
747 string s = Renderer.ToString().Replace("\r\n", "\n").Replace('\r', '\n');
748 string[] Rows = s.Split('\n');
749 int i, c = Rows.Length;
750
751 if (c > 0 && string.IsNullOrEmpty(Rows[c - 1]))
752 c--;
753
754 for (i = 0; i < c; i++)
755 {
756 this.Output.Append(Rows[i]);
757 this.Output.AppendLine(SuffixFirstRow);
758 SuffixFirstRow = SuffixNextRows;
759 }
760 }
761 }
762
769 private Task PrefixSuffixedBlock(ChunkedList<MarkdownElement> Children, string Prefix, string Suffix)
770 {
771 return this.PrefixSuffixedBlock(Children, Prefix, Prefix, Suffix, Suffix);
772 }
773
782 private async Task PrefixSuffixedBlock(ChunkedList<MarkdownElement> Children, string PrefixFirstRow, string PrefixNextRows,
783 string SuffixFirstRow, string SuffixNextRows)
784 {
786 {
787 await Renderer.Render(Children);
788
789 string s = Renderer.ToString().Replace("\r\n", "\n").Replace('\r', '\n');
790 string[] Rows = s.Split('\n');
791 int i, c = Rows.Length;
792
793 if (c > 0 && string.IsNullOrEmpty(Rows[c - 1]))
794 c--;
795
796 for (i = 0; i < c; i++)
797 {
798 this.Output.Append(PrefixFirstRow);
799 this.Output.Append(Rows[i]);
800 this.Output.AppendLine(SuffixFirstRow);
801 PrefixFirstRow = PrefixNextRows;
802 SuffixFirstRow = SuffixNextRows;
803 }
804 }
805 }
806
807 #endregion
808
809 #region Block elements
810
815 public override async Task Render(BlockQuote Element)
816 {
817 await this.PrefixedBlock(Element.Children, ">\t");
818 this.Output.AppendLine();
819 }
820
825 public override async Task Render(BulletList Element)
826 {
827 await this.RenderChildren(Element);
828 this.Output.AppendLine();
829 }
830
835 public override async Task Render(CenterAligned Element)
836 {
837 await this.PrefixSuffixedBlock(Element.Children, ">>", "<<");
838 this.Output.AppendLine();
839 }
840
845 public override async Task Render(CodeBlock Element)
846 {
847 if (this.portableSyntax)
848 {
850
851 if (!(Renderer is null))
852 {
853 try
854 {
855 if (await Renderer.RenderMarkdown(this, Element.Rows, Element.Language, Element.Indent, Element.Document))
856 return;
857 }
858 catch (Exception)
859 {
860 // Ignore
861 }
862 }
863 }
864
865 int Max = 2;
866
867 foreach (string Row in Element.Rows)
868 {
869 int i = 0;
870
871 foreach (char ch in Row)
872 {
873 if (ch == '`')
874 i++;
875 else
876 {
877 if (i > Max)
878 Max = i;
879
880 i = 0;
881 }
882 }
883
884 if (i > Max)
885 Max = i;
886 }
887
888 string s = new string('`', Max + 1);
889
890 this.Output.Append(s);
891 this.Output.AppendLine(Element.Language);
892
893 foreach (string Row in Element.Rows)
894 this.Output.AppendLine(Row);
895
896 this.Output.AppendLine(s);
897 this.Output.AppendLine();
898 }
899
904 public override Task Render(CommentBlock Element)
905 {
906 return Task.CompletedTask;
907 }
908
913 public override async Task Render(DefinitionDescriptions Element)
914 {
915 await this.PrefixedBlock(Element.Children, ":\t", ":\t");
916 this.Output.AppendLine();
917 }
918
923 public override async Task Render(DefinitionList Element)
924 {
925 await this.RenderChildren(Element);
926 this.Output.AppendLine();
927 }
928
933 public override async Task Render(DefinitionTerms Element)
934 {
935 ChunkNode<MarkdownElement> Loop = Element.Children.FirstChunk;
936 int i, c;
937
938 while (!(Loop is null))
939 {
940 for (i = Loop.Start, c = Loop.Pos; i < c; i++)
941 {
942 await Loop[i].Render(this);
943 this.Output.AppendLine();
944 }
945
946 Loop = Loop.Next;
947 }
948 }
949
954 public override async Task Render(DeleteBlocks Element)
955 {
956 await this.PrefixedBlock(Element.Children, "->\t");
957 this.Output.AppendLine();
958 }
959
964 public override Task Render(Footnote Element)
965 {
966 return this.RenderChildren(Element);
967 }
968
973 public override async Task Render(Header Element)
974 {
975 if (Element.Prefix)
976 {
977 this.Output.Append(Element.Row);
978 this.Output.Append(' ');
979 }
980
981 await this.RenderChildren(Element);
982 this.Output.AppendLine();
983
984 if (!Element.Prefix)
985 this.Output.AppendLine(Element.Row);
986
987 this.Output.AppendLine();
988 }
989
994 public override Task Render(HorizontalRule Element)
995 {
996 this.Output.AppendLine(Element.Row);
997 this.Output.AppendLine();
998
999 return Task.CompletedTask;
1000 }
1001
1006 public override async Task Render(HtmlBlock Element)
1007 {
1008 await this.RenderChildren(Element);
1009 this.Output.AppendLine();
1010 }
1011
1016 public override async Task Render(InsertBlocks Element)
1017 {
1018 await this.PrefixedBlock(Element.Children, "+>\t");
1019 this.Output.AppendLine();
1020 }
1021
1026 public override Task Render(InvisibleBreak Element)
1027 {
1028 this.Output.AppendLine(Element.Row);
1029 this.Output.AppendLine();
1030
1031 return Task.CompletedTask;
1032 }
1033
1038 public override async Task Render(LeftAligned Element)
1039 {
1040 await this.PrefixedBlock(Element.Children, "<<");
1041 this.Output.AppendLine();
1042 }
1043
1048 public override async Task Render(MarginAligned Element)
1049 {
1050 await this.PrefixSuffixedBlock(Element.Children, "<<", ">>");
1051 this.Output.AppendLine();
1052 }
1053
1058 public override Task Render(NestedBlock Element)
1059 {
1060 return this.RenderChildren(Element);
1061 }
1062
1067 public override async Task Render(NumberedItem Element)
1068 {
1069 string Prefix;
1070
1071 if (Element.NumberExplicit)
1072 Prefix = Element.Number.ToString() + ".\t";
1073 else
1074 Prefix = "#.\t";
1075
1076 await this.PrefixedBlock(Element.Child, Prefix, "\t");
1077
1078 if (Element.Child.IsBlockElement)
1079 this.Output.AppendLine();
1080 }
1081
1086 public override async Task Render(NumberedList Element)
1087 {
1088 await this.RenderChildren(Element);
1089 this.Output.AppendLine();
1090 }
1091
1096 public override async Task Render(Paragraph Element)
1097 {
1098 await this.RenderChildren(Element);
1099
1100 this.Output.AppendLine();
1101 this.Output.AppendLine();
1102 }
1103
1108 public override async Task Render(RightAligned Element)
1109 {
1110 await this.SuffixedBlock(Element.Children, ">>");
1111 this.Output.AppendLine();
1112 }
1113
1118 public override Task Render(Sections Element)
1119 {
1120 if (!string.IsNullOrEmpty(Element.InitialRow))
1121 {
1122 this.Output.AppendLine(Element.InitialRow);
1123 this.Output.AppendLine();
1124 }
1125
1126 return this.RenderChildren(Element);
1127 }
1128
1133 public override Task Render(SectionSeparator Element)
1134 {
1135 this.Output.AppendLine(Element.Row);
1136 this.Output.AppendLine();
1137
1138 return Task.CompletedTask;
1139 }
1140
1145 public override async Task Render(Table Element)
1146 {
1147 int[] Widths = new int[Element.Columns];
1148 int i, c, d;
1149
1150 string[][] Headers = new string[c = Element.Headers.Length][];
1151 for (i = 0; i < c; i++)
1152 Headers[i] = await this.Render(Element.Headers[i], Element.HeaderCellAlignments[i], Widths, Element);
1153
1154 string[][] Rows = new string[d = Element.Rows.Length][];
1155 for (i = 0; i < d; i++)
1156 Rows[i] = await this.Render(Element.Rows[i], Element.RowCellAlignments[i], Widths, Element);
1157
1158 for (i = 0; i < c; i++)
1159 this.Render(Headers[i], Widths, Element);
1160
1161 foreach (string Headline in Element.ColumnAlignmentDefinitions)
1162 {
1163 this.Output.Append('|');
1164 this.Output.Append(Headline);
1165 }
1166
1167 this.Output.AppendLine("|");
1168
1169 for (i = 0; i < d; i++)
1170 this.Render(Rows[i], Widths, Element);
1171
1172 bool NewLine = false;
1173
1174 if (!string.IsNullOrEmpty(Element.Caption))
1175 {
1176 this.Output.Append('[');
1177 this.Output.Append(Element.Caption);
1178 this.Output.Append(']');
1179 NewLine = true;
1180 }
1181
1182 if (!string.IsNullOrEmpty(Element.Id))
1183 {
1184 this.Output.Append('[');
1185 this.Output.Append(Element.Id);
1186 this.Output.Append(']');
1187 NewLine = true;
1188 }
1189
1190 if (NewLine)
1191 this.Output.AppendLine();
1192
1193 this.Output.AppendLine();
1194 }
1195
1196 private void Render(string[] Elements, int[] Widths, Table Element)
1197 {
1198 string s;
1199 int i, j, k;
1200
1201 this.Output.Append('|');
1202
1203 for (i = 0; i < Element.Columns;)
1204 {
1205 s = Elements[i];
1206 if (s is null)
1207 continue;
1208
1209 this.Output.Append(' ');
1210 this.Output.Append(s);
1211 j = Widths[i] - s.Length;
1212 k = 1;
1213
1214 i++;
1215 while (i < Element.Columns && Elements[i] is null)
1216 {
1217 j += Widths[i++];
1218 k++;
1219 }
1220
1221 while (j-- > 0)
1222 this.Output.Append(' ');
1223
1224 while (k-- > 0)
1225 this.Output.Append('|');
1226 }
1227
1228 this.Output.AppendLine();
1229 }
1230
1231 private async Task<string[]> Render(MarkdownElement[] Elements, TextAlignment?[] Alignments, int[] Widths, Table Element)
1232 {
1234 {
1235 string[] Result = new string[Element.Columns];
1236 string s;
1238 TextAlignment? Alignment;
1239 int Len, LastLen;
1240 int i, j;
1241
1242 for (i = 0; i < Element.Columns; i++)
1243 {
1244 E = Elements[i];
1245 if (E is null)
1246 continue;
1247
1248 await E.Render(Renderer);
1249 s = Renderer.ToString();
1250 Renderer.Clear();
1251
1252 Alignment = Alignments[i];
1253 if (Alignment.HasValue)
1254 {
1255 switch (Alignment.Value)
1256 {
1257 case TextAlignment.Left:
1258 s = "<<" + s;
1259 break;
1260
1261 case TextAlignment.Right:
1262 s += ">>";
1263 break;
1264
1265 case TextAlignment.Center:
1266 s = ">>" + s + "<<";
1267 break;
1268 }
1269 }
1270
1271 Result[i] = s;
1272
1273 LastLen = s.Length + 2; // One space on each side of content.
1274 j = i + 1;
1275 while (j < Element.Columns && Elements[j] is null)
1276 {
1277 Result[j++] = null;
1278 LastLen++; // One additional pipe character
1279 }
1280
1281 j -= i;
1282
1283 Len = LastLen / j;
1284 LastLen -= (j - 1) * Len;
1285
1286 while (j-- > 1)
1287 {
1288 if (Widths[i] < Len)
1289 Widths[i] = Len;
1290
1291 i++;
1292 }
1293
1294 if (Widths[i] < LastLen)
1295 Widths[i] = LastLen;
1296 }
1297
1298 return Result;
1299 }
1300 }
1301
1306 public override async Task Render(TaskItem Element)
1307 {
1308 await this.PrefixedBlock(Element.Child, Element.IsChecked ? "[x]\t" : "[ ]\t", "\t");
1309
1310 if (Element.Child.IsBlockElement)
1311 this.Output.AppendLine();
1312 }
1313
1318 public override async Task Render(TaskList Element)
1319 {
1320 await this.RenderChildren(Element);
1321 this.Output.AppendLine();
1322 }
1323
1328 public override async Task Render(UnnumberedItem Element)
1329 {
1330 await this.PrefixedBlock(Element.Child, Element.Prefix + "\t", "\t");
1331
1332 if (Element.Child.IsBlockElement)
1333 this.Output.AppendLine();
1334 }
1335
1336 #endregion
1337
1338 }
1339}
Converts an element to a markdown string.
Definition: ToMarkdown.cs:23
static string ImageToMarkdown(SKImage Image)
Converts an image to Markdown.
Definition: ToMarkdown.cs:369
static string MatrixToMarkdown(IMatrix Matrix)
Converts a matrix to Markdown.
Definition: ToMarkdown.cs:86
static string PixelsToMarkdown(PixelInformation Pixels)
Converts pixels to Markdown.
Definition: ToMarkdown.cs:343
static string GraphToMarkdown(Graph Graph)
Converts a graph to Markdown.
Definition: ToMarkdown.cs:318
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,...
static async Task< object > TransformXml(XmlDocument Xml, Variables Variables)
Transforms XML to an object that is easier to visualize.
static string Encode(string s)
Encodes all special characters in a string so that it can be included in a markdown document without ...
bool TryGetFootnote(string Key, out Footnote Footnote)
Tries to get a footnote, given its key.
IEnumerable< string > FootnoteOrder
Order of footnotes.
MarkdownDocument Detail
Detail document of a master document.
static Task< MarkdownDocument > CreateAsync(string MarkdownText, params Type[] TransparentExceptionTypes)
Contains a markdown document. This markdown document class supports original markdown,...
Contains settings that the Markdown parser uses to customize its behavior.
Represents a block quote in a markdown document.
Definition: BlockQuote.cs:11
Represents a bullet list in a markdown document.
Definition: BulletList.cs:11
Represents a center-aligned set of blocks in a markdown document.
Represents a code block in a markdown document.
Definition: CodeBlock.cs:17
Represents a comment block in a markdown document.
Definition: CommentBlock.cs:10
Represents a definition list in a markdown document.
Represents inserted blocks in a markdown document.
Definition: DeleteBlocks.cs:11
bool Referenced
If the Footnote has been referenced during rendering, and therefore needs to be shown at the end of t...
Definition: Footnote.cs:51
Represents a header in a markdown document.
Definition: Header.cs:15
bool Prefix
If header is defined using a prefix.
Definition: Header.cs:132
string Row
Original Row generating the horizontal rule.
Represents a block of HTML in a markdown document.
Definition: HtmlBlock.cs:11
Represents inserted blocks in a markdown document.
Definition: InsertBlocks.cs:11
Represents a left-aligned set of blocks in a markdown document.
Definition: LeftAligned.cs:11
Represents a margin-aligned set of blocks in a markdown document.
Represents a nested block with no special formatting rules in a markdown document.
Definition: NestedBlock.cs:12
Represents a numbered item in an ordered list.
Definition: NumberedItem.cs:10
Represents a numbered list in a markdown document.
Definition: NumberedList.cs:11
Represents a paragraph in a markdown document.
Definition: Paragraph.cs:11
Represents a right-aligned set of blocks in a markdown document.
Definition: RightAligned.cs:11
Represents a sequence of sections.
Definition: Sections.cs:11
Represents a table in a markdown document.
Definition: Table.cs:11
MarkdownElement[][] Headers
Headers in table.
Definition: Table.cs:55
MarkdownElement[][] Rows
Rows in table.
Definition: Table.cs:60
Represents a task item in a task list.
Definition: TaskItem.cs:10
Represents a task list in a markdown document.
Definition: TaskList.cs:11
Represents an unnumbered item in an ordered list.
Abstract base class for all markdown elements.
int? Height
Height of media item, if available.
int? Width
Width of media item, if available.
string Delimiter
Delimiter string used to identify emoji.
Represents an HTML entity in Unicode format.
MultimediaItem[] Items
Multimedia items.
Definition: Multimedia.cs:41
Renders portable Markdown from a Markdown document.
override Task Render(CommentBlock Element)
Renders Element .
override Task Render(InlineHTML Element)
Renders Element .
override Task Render(InvisibleBreak Element)
Renders Element .
override async Task Render(MarginAligned Element)
Renders Element .
override async Task Render(Header Element)
Renders Element .
override async Task Render(Delete Element)
Renders Element .
override async Task RenderFootnotes()
Renders footnotes.
override async Task Render(FootnoteReference Element)
Renders Element .
override async Task Render(SuperScript Element)
Renders Element .
MarkdownRenderer(StringBuilder Output, MarkdownDocument Document)
Renders portable Markdown from a Markdown document.
override Task Render(InlineText Element)
Renders Element .
override async Task Render(Link Element)
Renders Element .
override Task Render(MultimediaReference Element)
Renders Element .
override Task Render(AutomaticLinkMail Element)
Renders Element .
override Task Render(HashTag Element)
Renders Element .
override async Task Render(Emphasize Element)
Renders Element .
override async Task Render(DefinitionDescriptions Element)
Renders Element .
MarkdownRenderer()
Renders portable Markdown from a Markdown document.
override async Task Render(DeleteBlocks Element)
Renders Element .
override Task Render(DetailsReference Element)
Renders Element .
override async Task Render(NumberedItem Element)
Renders Element .
async Task RenderObject(object Result, bool AloneInParagraph, Variables Variables)
Generates Markdown from Script output.
override Task Render(NestedBlock Element)
Renders Element .
override async Task Render(DefinitionList Element)
Renders Element .
MarkdownRenderer(StringBuilder Output)
Renders portable Markdown from a Markdown document.
override async Task Render(BulletList Element)
Renders Element .
override Task Render(Footnote Element)
Renders Element .
override Task Render(LineBreak Element)
Renders Element .
override async Task Render(Abbreviation Element)
Renders Element .
override async Task Render(TaskList Element)
Renders Element .
override async Task Render(InsertBlocks Element)
Renders Element .
override Task Render(AutomaticLinkUrl Element)
Renders Element .
override Task Render(InlineCode Element)
Renders Element .
override async Task Render(Underline Element)
Renders Element .
override Task Render(HorizontalRule Element)
Renders Element .
override async Task Render(Table Element)
Renders Element .
override async Task Render(RightAligned Element)
Renders Element .
override async Task Render(Insert Element)
Renders Element .
override async Task Render(UnnumberedItem Element)
Renders Element .
override async Task Render(Strong Element)
Renders Element .
override Task Render(HtmlEntity Element)
Renders Element .
override async Task Render(HtmlBlock Element)
Renders Element .
override Task Render(SectionSeparator Element)
Renders Element .
override async Task Render(StrikeThrough Element)
Renders Element .
bool PortableSyntax
If a portable syntax of markdown is to be generated (true), or if generated Markdown is to be process...
MarkdownRenderer(MarkdownDocument Document)
Renders portable Markdown from a Markdown document.
override Task Render(Sections Element)
Renders Element .
override Task Render(HtmlEntityUnicode Element)
Renders Element .
override async Task Render(CodeBlock Element)
Renders Element .
override async Task Render(SubScript Element)
Renders Element .
override async Task Render(BlockQuote Element)
Renders Element .
override Task Render(MetaReference Element)
Renders Element .
override async Task Render(InlineScript Element)
Renders Element .
override async Task Render(DefinitionTerms Element)
Renders Element .
override async Task Render(LinkReference Element)
Renders Element .
override Task Render(EmojiReference Element)
Renders Element .
override async Task Render(TaskItem Element)
Renders Element .
override Task Render(Model.SpanElements.Multimedia Element)
Renders Element .
override async Task Render(NumberedList Element)
Renders Element .
override async Task Render(Paragraph Element)
Renders Element .
override async Task Render(CenterAligned Element)
Renders Element .
override async Task Render(LeftAligned Element)
Renders Element .
Abstract base class for Markdown renderers.
Definition: Renderer.cs:15
async Task< bool > Render(ChunkedList< MarkdownElement > Elements)
Renders a collection of elements.
Definition: Renderer.cs:191
readonly StringBuilder Output
Renderer output.
Definition: Renderer.cs:19
void Clear()
Clears the underlying StringBuilder.
Definition: Renderer.cs:138
virtual async Task RenderDocument(MarkdownDocument Document, bool Inclusion)
Renders a document.
Definition: Renderer.cs:76
Task RenderChildren(MarkdownElementChildren Element)
Renders the children of Element .
Definition: Renderer.cs:147
override string ToString()
Returns the renderer output.
Definition: Renderer.cs:130
MarkdownDocument Document
Reference to Markdown document being processed.
Definition: Renderer.cs:24
Renderer()
Abstract base class for Markdown renderers.
Definition: Renderer.cs:29
Helps with common XML-related tasks.
Definition: XML.cs:21
static string HtmlValueEncode(string s)
Differs from Encode(String), in that it does not encode the aposotrophe or the quote.
Definition: XML.cs:211
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Definition: Log.cs:828
Node referencing a chunk in a ChunkedList<T>
Definition: ChunkNode.cs:11
ChunkNode< T > Next
Next chunk
Definition: ChunkNode.cs:26
int Pos
Index after the last element in chunk.
Definition: ChunkNode.cs:51
int Start
Index of first element in chunk.
Definition: ChunkNode.cs:46
A chunked list is a linked list of chunks of objects of type T .
Definition: ChunkedList.cs:54
Base class for all types of elements.
Definition: Element.cs:14
Euler's number.
Definition: E.cs:12
Base class for graphs.
Definition: Graph.cs:88
Contains pixel information
ToMatrix(ScriptNode Operand, bool NullCheck, int Start, int Length, Expression Expression)
To-Matrix operator.
Definition: ToMatrix.cs:22
Collection of variables.
Definition: Variables.cs:25
Interface for multimedia content Markdown renderers.
Basic interface for matrices.
Definition: IMatrix.cs:7
Interface for objects that can be converted into matrices.
Definition: IToMatrix.cs:9
Definition: ImplTypes.g.cs:58
TextAlignment
Text alignment of contents.