From 17ee6d6a79ed7d1f5e681cc30e647b66f978bea3 Mon Sep 17 00:00:00 2001 From: Juan Osorio Date: Wed, 20 Nov 2024 11:51:34 -0800 Subject: [PATCH 1/2] MarkdownTextBlock: Enable/Disable built in extensions --- .../MarkdownTextBlockCustomSample.xaml | 67 ++++++----- .../src/MarkdownTextBlock.xaml.cs | 107 ++++++++++++++++-- .../src/Renderers/WinUIRenderer.cs | 35 ------ 3 files changed, 139 insertions(+), 70 deletions(-) diff --git a/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml index 7173b399d..dac21c75c 100644 --- a/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml +++ b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml @@ -1,12 +1,13 @@ - - + + @@ -15,30 +16,40 @@ - + - - + + - - + + diff --git a/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs b/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs index efba3cb4b..597b02ec8 100644 --- a/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs +++ b/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs @@ -3,6 +3,9 @@ // See the LICENSE file in the project root for more information. using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers; +using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers.ObjectRenderers; +using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers.ObjectRenderers.Extensions; +using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers.ObjectRenderers.Inlines; using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.TextElements; using Markdig; @@ -13,7 +16,7 @@ public partial class MarkdownTextBlock : Control { private const string MarkdownContainerName = "MarkdownContainer"; private Grid? _container; - private MarkdownPipeline _pipeline; + private MarkdownPipeline _pipeline = null!; private MyFlowDocument _document; private WinUIRenderer? _renderer; @@ -42,6 +45,65 @@ public string Text set => SetValue(TextProperty, value); } +#region Built in Extensions + + private static readonly DependencyProperty UseEmphasisExtrasProperty = DependencyProperty.Register( + nameof(UseEmphasisExtras), + typeof(bool), + typeof(MarkdownTextBlock), + new PropertyMetadata(false)); + public bool UseEmphasisExtras + { + get => (bool)GetValue(UseEmphasisExtrasProperty); + set => SetValue(UseEmphasisExtrasProperty, value); + } + + private static readonly DependencyProperty UsePipeTablesProperty = DependencyProperty.Register( + nameof(UsePipeTables), + typeof(bool), + typeof(MarkdownTextBlock), + new PropertyMetadata(false)); + public bool UsePipeTables + { + get => (bool)GetValue(UsePipeTablesProperty); + set => SetValue(UsePipeTablesProperty, value); + } + + private static readonly DependencyProperty UseListExtrasProperty = DependencyProperty.Register( + nameof(UseListExtras), + typeof(bool), + typeof(MarkdownTextBlock), + new PropertyMetadata(false)); + public bool UseListExtras + { + get => (bool)GetValue(UseListExtrasProperty); + set => SetValue(UseListExtrasProperty, value); + } + + private static readonly DependencyProperty UseTaskListsProperty = DependencyProperty.Register( + nameof(UseTaskLists), + typeof(bool), + typeof(MarkdownTextBlock), + new PropertyMetadata(false)); + public bool UseTaskLists + { + get => (bool)GetValue(UseTaskListsProperty); + set => SetValue(UseTaskListsProperty, value); + } + + private static readonly DependencyProperty UseAutoLinksProperty = DependencyProperty.Register( + nameof(UseAutoLinks), + typeof(bool), + typeof(MarkdownTextBlock), + new PropertyMetadata(false)); + public bool UseAutoLinks + { + get => (bool)GetValue(UseAutoLinksProperty); + set => SetValue(UseAutoLinksProperty, value); + } + + #endregion + private static void OnConfigChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is MarkdownTextBlock self && e.NewValue != null) @@ -62,17 +124,23 @@ public MarkdownTextBlock() { this.DefaultStyleKey = typeof(MarkdownTextBlock); _document = new MyFlowDocument(); - _pipeline = new MarkdownPipelineBuilder() - .UseEmphasisExtras() - .UseAutoLinks() - .UseTaskLists() - .UsePipeTables() - .Build(); } protected override void OnApplyTemplate() { base.OnApplyTemplate(); + + var pipelineBuilder = new MarkdownPipelineBuilder(); + + // NOTE: Order matters here + if (UseEmphasisExtras) pipelineBuilder = pipelineBuilder.UseEmphasisExtras(); + if (UsePipeTables) pipelineBuilder = pipelineBuilder.UsePipeTables(); + if (UseListExtras) pipelineBuilder = pipelineBuilder.UseListExtras(); + if (UseTaskLists) pipelineBuilder = pipelineBuilder.UseTaskLists(); + if (UseAutoLinks) pipelineBuilder = pipelineBuilder.UseAutoLinks(); + + _pipeline = pipelineBuilder.Build(); + _container = (Grid)GetTemplateChild(MarkdownContainerName); _container.Children.Clear(); _container.Children.Add(_document.RichTextBlock); @@ -111,6 +179,31 @@ private void Build() if (_renderer == null) { _renderer = new WinUIRenderer(_document, Config); + + // Default block renderers + _renderer.ObjectRenderers.Add(new CodeBlockRenderer()); + _renderer.ObjectRenderers.Add(new ListRenderer()); + _renderer.ObjectRenderers.Add(new HeadingRenderer()); + _renderer.ObjectRenderers.Add(new ParagraphRenderer()); + _renderer.ObjectRenderers.Add(new QuoteBlockRenderer()); + _renderer.ObjectRenderers.Add(new ThematicBreakRenderer()); + _renderer.ObjectRenderers.Add(new HtmlBlockRenderer()); + + // Default inline renderers + if (UseAutoLinks) _renderer.ObjectRenderers.Add(new AutoLinkInlineRenderer()); + _renderer.ObjectRenderers.Add(new CodeInlineRenderer()); + _renderer.ObjectRenderers.Add(new DelimiterInlineRenderer()); + _renderer.ObjectRenderers.Add(new EmphasisInlineRenderer()); + _renderer.ObjectRenderers.Add(new HtmlEntityInlineRenderer()); + _renderer.ObjectRenderers.Add(new LineBreakInlineRenderer()); + _renderer.ObjectRenderers.Add(new LinkInlineRenderer()); + _renderer.ObjectRenderers.Add(new LiteralInlineRenderer()); + _renderer.ObjectRenderers.Add(new ContainerInlineRenderer()); + + // Extension renderers + if (UsePipeTables) _renderer.ObjectRenderers.Add(new TableRenderer()); + if (UseTaskLists) _renderer.ObjectRenderers.Add(new TaskListRenderer()); + _renderer.ObjectRenderers.Add(new HtmlInlineRenderer()); } _pipeline.Setup(_renderer); ApplyText(false); diff --git a/components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs b/components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs index af4d6cb01..9c82d12ae 100644 --- a/components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs +++ b/components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs @@ -31,12 +31,6 @@ public WinUIRenderer(MyFlowDocument document, MarkdownConfig config) FlowDocument = document; // set style _stack.Push(FlowDocument); - LoadOverridenRenderers(); - } - - private void LoadOverridenRenderers() - { - LoadRenderers(); } public override object Render(MarkdownObject markdownObject) @@ -50,7 +44,6 @@ public void ReloadDocument() _stack.Clear(); FlowDocument.RichTextBlock.Blocks.Clear(); _stack.Push(FlowDocument); - LoadOverridenRenderers(); } public void WriteLeafInline(LeafBlock leafBlock) @@ -143,32 +136,4 @@ private static void AddInline(IAddChild parent, IAddChild inline) { parent.AddChild(inline); } - - protected virtual void LoadRenderers() - { - // Default block renderers - ObjectRenderers.Add(new CodeBlockRenderer()); - ObjectRenderers.Add(new ListRenderer()); - ObjectRenderers.Add(new HeadingRenderer()); - ObjectRenderers.Add(new ParagraphRenderer()); - ObjectRenderers.Add(new QuoteBlockRenderer()); - ObjectRenderers.Add(new ThematicBreakRenderer()); - ObjectRenderers.Add(new HtmlBlockRenderer()); - - // Default inline renderers - ObjectRenderers.Add(new AutoLinkInlineRenderer()); - ObjectRenderers.Add(new CodeInlineRenderer()); - ObjectRenderers.Add(new DelimiterInlineRenderer()); - ObjectRenderers.Add(new EmphasisInlineRenderer()); - ObjectRenderers.Add(new HtmlEntityInlineRenderer()); - ObjectRenderers.Add(new LineBreakInlineRenderer()); - ObjectRenderers.Add(new LinkInlineRenderer()); - ObjectRenderers.Add(new LiteralInlineRenderer()); - ObjectRenderers.Add(new ContainerInlineRenderer()); - - // Extension renderers - ObjectRenderers.Add(new TableRenderer()); - ObjectRenderers.Add(new TaskListRenderer()); - ObjectRenderers.Add(new HtmlInlineRenderer()); - } } From 255721cc681c5e0b76d50c2a5efe25ce17ec9b3c Mon Sep 17 00:00:00 2001 From: Juan Osorio Date: Thu, 28 Nov 2024 14:50:19 -0800 Subject: [PATCH 2/2] Move properties to their own file, add comments, add hardline break support --- .../MarkdownTextBlockCustomSample.xaml | 70 ++++---- .../src/MarkdownTextBlock.Properties.cs | 150 ++++++++++++++++++ .../src/MarkdownTextBlock.xaml.cs | 85 +--------- 3 files changed, 183 insertions(+), 122 deletions(-) create mode 100644 components/MarkdownTextBlock/src/MarkdownTextBlock.Properties.cs diff --git a/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml index dac21c75c..fcfe22d9e 100644 --- a/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml +++ b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml @@ -1,13 +1,12 @@ - + @@ -16,40 +15,35 @@ - + - - + + - - + + diff --git a/components/MarkdownTextBlock/src/MarkdownTextBlock.Properties.cs b/components/MarkdownTextBlock/src/MarkdownTextBlock.Properties.cs new file mode 100644 index 000000000..3ff818142 --- /dev/null +++ b/components/MarkdownTextBlock/src/MarkdownTextBlock.Properties.cs @@ -0,0 +1,150 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace CommunityToolkit.Labs.WinUI.MarkdownTextBlock; + +public partial class MarkdownTextBlock +{ + /// + /// Identifies the dependency property. + /// + private static readonly DependencyProperty ConfigProperty = DependencyProperty.Register( + nameof(Config), + typeof(MarkdownConfig), + typeof(MarkdownTextBlock), + new PropertyMetadata(null, OnConfigChanged) + ); + + /// + /// Identifies the dependency property. + /// + private static readonly DependencyProperty TextProperty = DependencyProperty.Register( + nameof(Text), + typeof(string), + typeof(MarkdownTextBlock), + new PropertyMetadata(null, OnTextChanged)); + + /// + /// Identifies the dependency property. + /// + private static readonly DependencyProperty UseEmphasisExtrasProperty = DependencyProperty.Register( + nameof(UseEmphasisExtras), + typeof(bool), + typeof(MarkdownTextBlock), + new PropertyMetadata(false)); + + /// + /// Identifies the dependency property. + /// + private static readonly DependencyProperty UsePipeTablesProperty = DependencyProperty.Register( + nameof(UsePipeTables), + typeof(bool), + typeof(MarkdownTextBlock), + new PropertyMetadata(false)); + + /// + /// Identifies the dependency property. + /// + private static readonly DependencyProperty UseListExtrasProperty = DependencyProperty.Register( + nameof(UseListExtras), + typeof(bool), + typeof(MarkdownTextBlock), + new PropertyMetadata(false)); + + /// + /// Identifies the dependency property. + /// + private static readonly DependencyProperty UseTaskListsProperty = DependencyProperty.Register( + nameof(UseTaskLists), + typeof(bool), + typeof(MarkdownTextBlock), + new PropertyMetadata(false)); + + /// + /// Identifies the dependency property. + /// + private static readonly DependencyProperty UseAutoLinksProperty = DependencyProperty.Register( + nameof(UseAutoLinks), + typeof(bool), + typeof(MarkdownTextBlock), + new PropertyMetadata(false)); + + /// + /// Identifies the dependency property. + /// + private static readonly DependencyProperty UseSoftlineBreakAsHardlineBreakProperty = DependencyProperty.Register( + nameof(UseSoftlineBreakAsHardlineBreak), + typeof(bool), + typeof(MarkdownTextBlock), + new PropertyMetadata(false)); + + public MarkdownConfig Config + { + get => (MarkdownConfig)GetValue(ConfigProperty); + set => SetValue(ConfigProperty, value); + } + + /// + /// Gets or sets the markdown text to display. + /// + public string Text + { + get => (string)GetValue(TextProperty); + set => SetValue(TextProperty, value); + } + + /// + /// If true, adds support for strikethroughs, superscript, subscript, inserted, and marked text. + /// + public bool UseEmphasisExtras + { + get => (bool)GetValue(UseEmphasisExtrasProperty); + set => SetValue(UseEmphasisExtrasProperty, value); + } + + /// + /// If true, adds support for GitHub-style pipe tables. + /// + public bool UsePipeTables + { + get => (bool)GetValue(UsePipeTablesProperty); + set => SetValue(UsePipeTablesProperty, value); + } + + /// + /// If true, adds support for alphabetic and roman numbering in lists. + /// + public bool UseListExtras + { + get => (bool)GetValue(UseListExtrasProperty); + set => SetValue(UseListExtrasProperty, value); + } + + /// + /// If true, adds support for GitHub-style task lists using the [ ] and [x] syntax. + /// + public bool UseTaskLists + { + get => (bool)GetValue(UseTaskListsProperty); + set => SetValue(UseTaskListsProperty, value); + } + + /// + /// If true, parses text that looks like URIs into hyperlinks (e.g. https://...). + /// + public bool UseAutoLinks + { + get => (bool)GetValue(UseAutoLinksProperty); + set => SetValue(UseAutoLinksProperty, value); + } + + /// + /// If true, considers single newlines as hardline breaks. + /// + public bool UseSoftlineBreakAsHardlineBreak + { + get => (bool)GetValue(UseSoftlineBreakAsHardlineBreakProperty); + set => SetValue(UseSoftlineBreakAsHardlineBreakProperty, value); + } +} diff --git a/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs b/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs index 597b02ec8..44369ff7a 100644 --- a/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs +++ b/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs @@ -20,90 +20,6 @@ public partial class MarkdownTextBlock : Control private MyFlowDocument _document; private WinUIRenderer? _renderer; - private static readonly DependencyProperty ConfigProperty = DependencyProperty.Register( - nameof(Config), - typeof(MarkdownConfig), - typeof(MarkdownTextBlock), - new PropertyMetadata(null, OnConfigChanged) - ); - - private static readonly DependencyProperty TextProperty = DependencyProperty.Register( - nameof(Text), - typeof(string), - typeof(MarkdownTextBlock), - new PropertyMetadata(null, OnTextChanged)); - - public MarkdownConfig Config - { - get => (MarkdownConfig)GetValue(ConfigProperty); - set => SetValue(ConfigProperty, value); - } - - public string Text - { - get => (string)GetValue(TextProperty); - set => SetValue(TextProperty, value); - } - -#region Built in Extensions - - private static readonly DependencyProperty UseEmphasisExtrasProperty = DependencyProperty.Register( - nameof(UseEmphasisExtras), - typeof(bool), - typeof(MarkdownTextBlock), - new PropertyMetadata(false)); - public bool UseEmphasisExtras - { - get => (bool)GetValue(UseEmphasisExtrasProperty); - set => SetValue(UseEmphasisExtrasProperty, value); - } - - private static readonly DependencyProperty UsePipeTablesProperty = DependencyProperty.Register( - nameof(UsePipeTables), - typeof(bool), - typeof(MarkdownTextBlock), - new PropertyMetadata(false)); - public bool UsePipeTables - { - get => (bool)GetValue(UsePipeTablesProperty); - set => SetValue(UsePipeTablesProperty, value); - } - - private static readonly DependencyProperty UseListExtrasProperty = DependencyProperty.Register( - nameof(UseListExtras), - typeof(bool), - typeof(MarkdownTextBlock), - new PropertyMetadata(false)); - public bool UseListExtras - { - get => (bool)GetValue(UseListExtrasProperty); - set => SetValue(UseListExtrasProperty, value); - } - - private static readonly DependencyProperty UseTaskListsProperty = DependencyProperty.Register( - nameof(UseTaskLists), - typeof(bool), - typeof(MarkdownTextBlock), - new PropertyMetadata(false)); - public bool UseTaskLists - { - get => (bool)GetValue(UseTaskListsProperty); - set => SetValue(UseTaskListsProperty, value); - } - - private static readonly DependencyProperty UseAutoLinksProperty = DependencyProperty.Register( - nameof(UseAutoLinks), - typeof(bool), - typeof(MarkdownTextBlock), - new PropertyMetadata(false)); - public bool UseAutoLinks - { - get => (bool)GetValue(UseAutoLinksProperty); - set => SetValue(UseAutoLinksProperty, value); - } - - #endregion - private static void OnConfigChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is MarkdownTextBlock self && e.NewValue != null) @@ -138,6 +54,7 @@ protected override void OnApplyTemplate() if (UseListExtras) pipelineBuilder = pipelineBuilder.UseListExtras(); if (UseTaskLists) pipelineBuilder = pipelineBuilder.UseTaskLists(); if (UseAutoLinks) pipelineBuilder = pipelineBuilder.UseAutoLinks(); + if (UseSoftlineBreakAsHardlineBreak) pipelineBuilder = pipelineBuilder.UseSoftlineBreakAsHardlineBreak(); _pipeline = pipelineBuilder.Build();