mirror of
https://github.com/xoofx/markdig.git
synced 2026-02-03 21:36:36 +00:00
Intercepting builtin tags? #57
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @yetanotherchris on GitHub (Sep 26, 2016).
In the readme you mention you can plug into the core parsing:
Is there an example of this you could share? I'm looking specifically for image and link tags (as I mentioned in your blog post) - I want to rewrite the urls.
The MarkdownSharp way of doing this is to hack the source, for example add an event handler call inside
private string DoImages(string text). Given your architecture I'm guessing it's a lot less messy in Markdig.@xoofx commented on GitHub (Sep 26, 2016):
There is currently no public callbacks specifically for post processing image links (or any block/inline elements in fact). The only callback that is being exposed is
MarkdownPipelineBuilder.DocumentProcessedfrom which you can postprocess aMarkdownDocument.You can also do this by calling directly the
Markdown.Parse, post-process the document and then render it with aHtmlRenderer.Then you can iterate over the inline links elements like this
doc.Descendants().OfType<LinkInline>()That's the easiest solution for now, though it is not the most efficient one, as the
Descendants()method is going to walkthrough all blocks and inlines only to return the ones you are interested in.While developing markdig, I tried to add some callbacks, but I was not really satisfied with the impact they had (in terms of performance, in terms of verbosity they induce for extension developers...etc.). The problem is that some extensions are sometimes transforming a tree and I was not sure how to handle this nicely, things like:
So there is some more thinking/work to be done in order to support efficiently this kind of scenario... Might be able to have a look later this week.
@Kryptos-FR commented on GitHub (Sep 26, 2016):
I'm also interested in this. Currently I can render a
MarkdownDocumentinto XAML (as text) with my custom renderer.But for creating a WPF document (i.e. an instance of the
FlowDocumentclass) using a renderer is not ideal: some post-process and transformations are required. Should I work directly on the syntax tree inside theMarkdownDocument?@xoofx commented on GitHub (Sep 26, 2016):
@Kryptos-FR not sure that the requested feature here could help your work (selective callback without having to re-visit the tree). In your case, you need to traverse all block and inline elements and create a WPF tree from them. The renderer provides mostly a visitor infrastructure but you can roll-up your own if it doesn't match your process. If you find no way to efficiently do this with the current API or there is just something missing in the renderer API that could be changed to help you, feel free to open another issue, we will look at this problem separately.
@yetanotherchris commented on GitHub (Sep 26, 2016):
Thanks for the pointer, actually the AST is fine for my needs although maybe a walker (similar to the pattern Antlr uses) might be a good strategy going forward, although the way it works now is fairly intuitive - it just needs a few docs. I'll happily add some examples.
Here's how I got it working for now, I haven't tested it with large documents yet though, but I can't see there being an issue.
Edit by @MihaZupan: Remove the recursive call to Walk that would cause N^2 visits.
@jasel-lewis commented on GitHub (Sep 26, 2019):
@xoofx First off, LOVE Markdig - THANK YOU!
+1 for me on this topic as well. I'm using Markdig within an ASP.NET MVC app and would like to manipulate the URLs generated for an inline image. The static Markdown content resides within a route construct and I'd like to pass in the controller and action names so that I can just use the image's filename in the Markdown (i.e.
*Image Caption*)) and get a full absolute path in the HTML output.I was super excited when I noticed the
GetDynamicUrlproperty of aLinkInlineand I see whatAutoIdentifierExtensionis doing with it, but my hopes were dashed when I noticed theInlineProcessordoes not fire any events such as theClosedevent thatAutoIdentifierExtensionis using on theHeadingBlockParser.I read your reply above and I understand the complexities involved. I'll probably end up just walking the
Descendantsas provided in the code sample posted by @yetanotherchris (thanks, @yetanotherchris!!). Nevertheless, it would be SUPER nice to hook into the processors using delegates to manipulate certain properties of the differingSyntaxes.@MihaZupan commented on GitHub (Sep 26, 2019):
@jasel-lewis Does the
Func<string, string> LinkRewriterexposed on theHtmlRenderersolve your use case?renderer.LinkRewriter = link => "somethingElse/" + link;I feel that post-processing the
MarkdownDocumentat the end is more appropriate for such changes.You should know that now there is a
Descendants<T>()method available to make simple modifications easier. It is currently missing an overloadwhere T: Inline, but that is a simple PR change away.@jasel-lewis commented on GitHub (Sep 27, 2019):
@MihaZupan Nice find! ...but unfortunately, no. Using
LinkRewriterrewrites every link (even header references). I want to solely rewrite image links (because they exist in static-content folders that are physically buried within the MVC construct). There is no way to tell (withLinkRewriter) if the link currently being rewritten belongs to aLinkInline.I like the way you think, however. I may create a PR which does something similar and adds a
LinkRewriterdelegate property to theLinkInlineRendererbecause you can do something like this:htmlRenderer.ObjectRenderers.Find<LinkInlineRenderer>();.As an extension to my prior post, this is how I went about modifying @yetanotherchris's solution - just in case any future on-looker cared:
Note: The
!l.Url.StartsWith("http")is to make an educated guess to ensure we didn't already assign a static URL within the Markdown syntax.Note2: Code was originally a recursive function per the code above from @yetanotherchris. As @MihaZupan pointed out, the
Walk(child)causes a huge, and unnecessary, performance issue. Got rid of it and refined the number of objects being inspected per the Linq query (untilDecendants<T>()gets fleshed out forInlines).@MihaZupan commented on GitHub (Sep 27, 2019):
Descendants already walks through all the child nodes. Doing it again recursively means you're visiting nodes N^2 times.
@JamesQMurphy commented on GitHub (Jan 14, 2020):
@jasel-lewis Thank you for posting that code! I'm just wondering if you or @yetanotherchris or anyone else considered hooking into the
RendererBase.ObjectWriteBeforeevent. This event, along with theObjectWriteAfterevent, does make theMarkdownObjectavailable, allowing you to determine if it's aLinkInlineor not.This is the approach I took:
@xoofx Also a big fan of Markdig, so let me echo @jasel-lewis 's thanks! 😃
@MihaZupan commented on GitHub (Jan 14, 2020):
I haven't concidered it before, but I suppose it should work just as fine.
I personally prefer post-processing the AST prior to rendering like so:
Where
document.Descendants().OfType<LinkInline>()can become
document.Descendants<LinkInline>()with a trivial PR.