-
Couldn't load subscription status.
- Fork 1.4k
Markdown + RSS Parser for .NET Standard, MarkdownTextBlock Style Improvements, Syntax Highlighting #1650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Markdown + RSS Parser for .NET Standard, MarkdownTextBlock Style Improvements, Syntax Highlighting #1650
Conversation
-Made required Parsing Classes and Enums public (I know I could have done InternalsVisibleTo, but then the Parser wouldn't be extensible. -Moved Parser to Microsoft.Toolkit.Services, seemed most relevant, but could be moved elsewhere.
-Moved DependecyProperties to top of definition. -Referenced Parser in documentation.
…atform rendering base class. This might need tweaks as it is almost a direct Port of XamlRenderer. -Broke down XamlRenderer and MarkdownRendererBase into partial classes for Blocks and Inline, as well as Properties.
… Xaml, and the name is easier to understand.
-Moved Superscript methods out of MarkdownRendererBase back to UWPMarkdownRenderer, as they are fixes for a UWP implementation. -Created CheckRenderMarkdownLink, split off of UWPMarkdownRenderer RenderMarkdownLink, it validates links before creation.
…t custom formatting into a Code Block, such as adding Syntax Highlighting.
|
@nmetulev I was thinking of adding Syntax Highlighting to the Code Blocks, (Using GitHub Style Prefixing of the block) e.g. ```c# makes public void Method()
{
}I found a library that could do it, at https://colorcode.codeplex.com/ which I could modify to use Spans for RichTextBlock, and SpannableStrings for Android (Using an interface or abstract class). I'm not sure how the license is compatible, it is a Microsoft Public License. I have added an Event to Handle processing Code Block Syntax rendering, would we want to roll built in Syntax Highlighting? |
…e inline with Presentation in Reddit and Github, in terms of color choice and Quote styling. -Inline Code elements are now much easier to see, they have a border, and customisable padding. These elements are customised separately from the Code Blocks. This is because they generally follow the current line's properties, such as formatting and font family. They having customisable paddings, border brushes, border thicknesses, background color and font family. They used to only be a different font family. -Prefixed Code Blocks now correctly collect the Programming Language Identifier. This Identifier is no longer rendered to the screen. -Separated the measurement based properties into a new .Dimensions.cs partial file for UWPMarkdownRenderer and MarkdownTextBlock. -Added some properties to the MarkdownTextBlock sample page, also added a demo CodeBlockResolveingEvent, for custom Syntax Highlighting.
|
I have made some much needed style changes to the default Markdown Style for the Markdown TextBlock. I also rebuilt the Code Inlines, so that they now are more than just a different font family, but actually have a Border, Background, etc. This should become the default style, but a Compat Style could be provided to anyone who wants to update to this version and keep their old styling, for some reason. |
…ide a inherited IRenderContext interface. This is because these parameters are UWP Specific. IRenderContext provides a useful container for the contract, holding the UI State.
|
@WilliamABradley wow, cool! I'll start reviewing this. I was just needing to do some Markdown parsing on a personal project and thought it'd be great if we could break this parser out. I wanted to look at some extensions for RichEditBox accepting/returning some basic Markdown, so I think this is a step towards that as well. |
…as done with a new Reference to WilliamABradley/ColorCode-Universal which is a fork from the old ColorCode Codeplex project, with a new RichTextBlockFormatter. -Fixed some Render Context structures. -Added some documentation for the new Properties and Events.
|
@michael-hawker @nmetulev I have added built in Syntax Highlighting! Isn't it glorious! Unfortunately there are some missing formats, and things I would like to tweak from ColorCode-Universal, such as the fact that XAML isn't recognised (but xml is), C# Method and Property coloring, etc. Since I ported the Library in my personal GitHub, and upgraded it there, there are no license conflicts with the UWP Community Toolkit. Also, @michael-hawker, if you take a look at https://github.com/WilliamABradley/ColorCode-Universal, you could use ColorCode.UWP to make a RichEditBox with Syntax Highlighting, such as a possible *Also, I will update all .md files in the documentation with Language prefixed Code Blocks, so that we get Syntax Highlighting in the documentation. |
|
Also Text Selection is a real mess right now and pretty broken (Before this PR too), I think it could be possible to make the Text Selection work across the different internal controls. Perhaps it could be done in a separate PR, but it just isn't there right now. Should we leave text selection off by default? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is amazing, definitely a great idea. Biggest change I'd request right now is regarding where the code sits. Microsoft.Toolkit.Services is not the right place for the parser. That package is for services such as Twitter and Facebook. Please create a new project to host the parser. How about Microsoft.Toolkit.Markdown?
| System.out.println("Hello world!"); | ||
| } | ||
|
|
||
| Starting with UWP Community Toolkit v1.4, you can also use GitHub code notification by creating a block surrounded by 3x\` (3 backticks). So: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to rewrite this sentence so the So at the end makes sense
| /// rendered. | ||
| /// </summary> | ||
| [Obsolete("Use Microsoft.Toolkit.Services.Markdown.MarkdownRenderedEventArgs instead.")] | ||
| public class MarkdownRenderedEventArgs : EventArgs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class should just extend the new class. Wouldn't the new class require developers to include the new package as well in order to use the event?
| <SolidColorBrush x:Key="MarkdownInlineCodeBackgroundBrush" Color="#FFDDDFE1" /> | ||
| <SolidColorBrush x:Key="MarkdownQuoteForeground" Color="#FF6E747C" /> | ||
| </ResourceDictionary> | ||
| <ResourceDictionary x:Key="Dark"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Dark theme seems broken?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have to set the Foreground color in the Properties Panel, when switching to Dark mode, as it allows you to change it.
|
@nmetulev I was thinking that, however, there is an RSS Parser in the same folder, although that doesn't interact with UI, so I can go that if you want? |
|
Yeah, the RSS parser is internal because it's needed by the bing service. We should probably move it to the same project as the markdown parser and make it public. |
|
@nmetulev Awesome, I can get on with that, making Microsoft.Toolkit.Parsers? Also, should I replace the Sample App's Async Code Coloring Code Panel, with a call to ColorCode-Universal RichTextBlockFormatter, which isn't asynchronous? |
|
Microsoft.Toolkit.Parsers sounds good What's the benefit of replacing the call with one that's not asynchronous? |
|
ColorCode-Universal uses regex and produces HTML, or a Colorized RichTextBlock (So its native), and it has greater support for a larger set of languages. The current implementation uses a WebView and JavaScript, so it takes longer to load, and doesn't support theme styling, etc. |
|
Ah, I see what you mean. Sounds good, go for it. |
…ect. -Made RSS Parser and it's types public. -Added CodeStyling property to MarkDownTextBlock for the built in Syntax Highlighter. -Added Build.bat for one-click simplicity.
docs/controls/MarkdownTextBlock.md
Outdated
| block.SetRenderer<InheritedUWPMarkdownRenderer>(); | ||
| ``` | ||
|
|
||
| This might require intimate knowledge of the implementation of the `UWPMarkdownRenderer`, take a look at the following: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change name to MarkdownRenderer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nmetulev Done.
… to make it easier to follow along. -Improved the DocFX note style, bringing it even more in-line with docs.microsoft.com.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GitHub stopped loading diffs for me, so I'll take a look at the other changes a bit later. Some initial small comments though from what I played with on the weekend.
| namespace Microsoft.Toolkit.Parsers | ||
| { | ||
| /// <summary> | ||
| /// Strong typed schema base class. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be handy to have more details here on what this is used for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used by the RSS Parser, and some of the Services like Bing? It is a base class for Schema based parsers.
| namespace Microsoft.Toolkit.Parsers.Core | ||
| { | ||
| /// <summary> | ||
| /// StringValue attribute. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
StringValue attribute used by...? extra pointers would be helpful here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used by the Bing Service, I believe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like it's an enum helper. Could be nice to elaborate the description here to The StringValue attribute is used as a helper to decorate enum values with string representations. Though I don't see where Bing actually reads these in...
Are we removing the old one in Microsoft.Toolkit.Uwp.Services as part of this change?
|
|
||
| namespace Microsoft.Toolkit.Parsers.Markdown.Enums | ||
| { | ||
| internal enum InlineParseMethod |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this different than MarkdownInlineType?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InlineParseMethod is used for identifying Inlines with TripChars, the other is for structure identification.
An inline type might have no MarkdownInlineType, private Inlines like BoldItalicInline which converts itself into a BoldInline, it is a workaround.
This stuff has always been here, I might clean it up / remove it in a new PR (Like with #1767 where I will likely remove the enums altogether).
|
|
||
| namespace Microsoft.Toolkit.Parsers.Markdown.Helpers | ||
| { | ||
| internal class LineInfo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this for tracking block positions?
If so, could be useful to expose for locating/highlighting text based on parsing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, this should be work for a PR based #1767, where we open up the internals of the Parser for tinkering.
Since you couldn't really do much with this info right now, and it would require considerable more work to expose, leave it for now.
This PR is big enough as it is :)
| } | ||
|
|
||
| if (markdown == null || markdown.Length < 6) | ||
| if (markdown == null || markdown.Length < 6 || start + 6 >= maxEnd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the '6' for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It ensures that the length of the string can possibly fit two sets of "***", which is required for Bold and Italic parsing. Without these, creating a BoldItalicInline will crash if prepended or appended to the text, due to the substring calls.
| return base.ToString(); | ||
| } | ||
|
|
||
| return string.Join("\r\n", Blocks); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might not have gotten to it yet. Is there a test that checks that the output of the MarkdownDocument toString is the same as what was passed in to Parse?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that code was before my PR :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be good to think about adding another test then that has a sample markdown text blob, gets read by the parser, and then the document gets serialized back to markdown and compare the results?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are numerous cases where this isn't done, or the returned ToString isn't the same is the input. Examples are the CodeBlock where it just returns the text. HorizontalRuleBlock only returns one kind of raw line, when there are several ways to do it, etc.
It could be done, but it would take some considerable reworking, possibly for a future PR like #1767 or future PRs.
| /// </summary> | ||
| internal abstract class MarkdownElement | ||
| public abstract class MarkdownElement | ||
| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there another block type we could use here on all elements? Trying to think if that'd be nicer than having to check class instances.
Also wondering if we want a common 'Text' property or if toString is sufficient. Or maybe 'DisplayText' which would have the text without the markup?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently the Text Property belongs to IInlineLeaf, as not all Inlines have text. And Blocks (Which inherit from MarkdownElement) definitely don't have a text property.
Unfortunately, Blocks aren't guaranteed to have Inlines or text either, so it makes it difficult to traverse the structure manually.
You would have to check the type using is or looking at the MarkdownBlock.Type and MarkdownInline.Type properties.
The way I would do it is:
switch(block)
{
case CodeBlock code:
var text = code.Text;
...
}|
|
||
| namespace Microsoft.Toolkit.Services.Rss |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this internal usage before too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep
| { | ||
| case "CSHARP": | ||
| case "CS": | ||
| language = "C#"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this not be in the parser somewhere vs the renderer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just for the header of the Sample App's Code Block that has a header specifying the language of the Code, just like docs.microsoft.com.
| } | ||
| } | ||
|
|
||
| private const string NoteGlyph = "\uE946"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be configurable? Or is it part of the Common Mark spec?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only for the Sample App, it is part of DocFX, so it isn't included in our CommonMark-ish parser.
…lkit into MakeMarkdownUniversalAgain
…lkit into MakeMarkdownUniversalAgain
…ting name, and avoids naming confusion with LinkReferenceBlock.
|
ping @nmetulev All dependent PRs are now merged :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. Make sure to pull latest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think that's the last of it, finally got the whole thing to load. Phew...
| /// <summary> | ||
| /// Regular expression of HTML tags to remove. | ||
| /// </summary> | ||
| private static readonly Regex RemoveHtmlTagsRegex = new Regex(@"(?></?\w+)(?>(?:[^>'""]+|'[^']*'|""[^""]*"")*)>"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put all these methods in the new StringExtensions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do
| namespace Microsoft.Toolkit.Parsers.Core | ||
| { | ||
| /// <summary> | ||
| /// StringValue attribute. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like it's an enum helper. Could be nice to elaborate the description here to The StringValue attribute is used as a helper to decorate enum values with string representations. Though I don't see where Bing actually reads these in...
Are we removing the old one in Microsoft.Toolkit.Uwp.Services as part of this change?
|
|
||
| if (newLine) | ||
| { | ||
| builder.Append("\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we using \n everywhere, are there cases where we should be using Environment.NewLine?
| switch (Style) | ||
| { | ||
| case ListStyle.Bulleted: | ||
| result.Append("* "); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason you add the space after the bullet here, but not after the '.' below? I'd assume we'd want a space after in both cases to be consistent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was a pre-existing implementation.
| @@ -10,26 +10,21 @@ | |||
| // THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. | |||
| // ****************************************************************** | |||
|
|
|||
| namespace Microsoft.Toolkit.Uwp.Services.Rss | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
??? This seems like an odd rename?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Git got a little confused.
|
|
||
| var border = new Border | ||
| { | ||
| Padding = new Thickness(0, 0, 0, paragraph.FontSize * 0.2), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Magic Number?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't change anything here, it was moved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed offline, was here before, we can worry about another day.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was an existing implementation.
UWP Community Toolkit.sln
Outdated
| EndProjectSection | ||
| EndProject | ||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Toolkit.Uwp.Notifications.JavaScript", "Microsoft.Toolkit.Uwp.Notifications.JavaScript\Microsoft.Toolkit.Uwp.Notifications.JavaScript.csproj", "{94F8D702-3A9D-4CFB-85C9-79FC5DBD8B22}" | ||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Uwp.Notifications.JavaScript", "Microsoft.Toolkit.Uwp.Notifications.JavaScript\Microsoft.Toolkit.Uwp.Notifications.JavaScript.csproj", "{94F8D702-3A9D-4CFB-85C9-79FC5DBD8B22}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we know why this guid changed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No idea? Perhaps pulling master?
| xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | ||
| xmlns:wrapPanel="using:Microsoft.Toolkit.Uwp.UI.Controls.WrapPanel" | ||
| mc:Ignorable="d"> | ||
| xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lots of whitespace changes, these don't lineup anymore. :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was Visual Studio, It is probably better because that means these will take less horizontal space.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just like my xaml attributes to line up, but maybe I'm weird that way...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would a major pain to fix all of the code comments :(
| using Microsoft.Toolkit.Parsers.Markdown.Blocks; | ||
| using Microsoft.Toolkit.Parsers.Markdown.Inlines; | ||
|
|
||
| namespace UnitTests.Markdown.Parse |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be a new bold+italic test suite?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned we can resolve in #1798.
| <Content Include="Assets\StoreLogo.png" /> | ||
| <Content Include="Assets\Wide310x150Logo.scale-200.png" /> | ||
| </ItemGroup> | ||
| <ItemGroup> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add a code block test since its new. Anything else new?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original Code Block test still works.
-Gave StringValueAttribute a better description. -Added OrdinalIgnoreCase to Common.IndexOf. -Fixed general feedback.
…lkit into MakeMarkdownUniversalAgain
|
@michael-hawker Made all changes against review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty close, for the Code Block unit test, I meant adding for parsing out the language name.
| /// <summary> | ||
| /// Regular expression for removing comments. | ||
| /// </summary> | ||
| private static readonly Regex RemoveCommentsRegex = new Regex("<!--.*?-->", RegexOptions.Singleline); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should preface these as Html comments/scripts/styles, eh?
| } | ||
|
|
||
| /// <summary> | ||
| /// Truncates the specified string to the specified length. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should mention it trims too.
-Added Backtick and Code language tests for Code Block.
|
@michael-hawker I performed the requested changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yay!



Moved Markdown Parser (along with RSS Parser) to new project
Microsoft.Toolkit.Parsers.Made required Parsing Classes and Enums public (I know I could have done InternalsVisibleTo, but then the Parser wouldn't be extensible.
Split the Markdown Parser from MarkdownTextBlock.
Create
IMarkdownRendererMarkdownRendererBase, make XamlRenderer inherit it.Replace JavaScript based Syntax Highlighter in Sample App with ColorCode-Universal.
Add CodeBlock addornments and DocFX formatting in Sample App.
Add Parsing of Html <a> tags into new LinkAnchorInline.
Fix rendering of Code Blocks nested in Lists.
I also did some Restyling of the default Markdown to be further in line with Reddit and GitHub.
PR Type
What kind of change does this PR introduce?
PR Checklist
Please check if your PR fulfills the following requirements:
Does this PR introduce a breaking change?
Namespaces for Parser elements change from Microsoft.Toolkit.Uwp.UI.Controls to Microsoft.Toolkit.Services.Markdown. This shouldn't matter too much, since most of this was marked as Internal anyways.
A lot of Internal Parsing Classes had to be made Public, as they are involved in creating the UI in the MarkdownTextblock, and any other Control based off of the Parser. It appears it was all documented anyway, but it increases the API surface.
Some RSS Parser and classes moved and changed namespaces, this is mostly fine, but there might need to be some deprecation warnings.
Other information
I am using this to create an Xamarin Android Markdown TextView, If I create that, I'm more than happy to add it to a future Microsoft.Toolkit.Android.UI.Controls Project :)
This would have to become the Microsoft Community Toolkit though.