How to implement custom markdown spec
See original GitHub issue- Markwon version: 4.1.0
First off I’d like to say thank you for this for the hard work, I’ve been trying to think of the best way to implement some custom Markdown spec features e.g.
img###(https://media.giphy.com/media/IcJ6n6VJNjRNS/giphy.gif)
I would create a standard markdown/html image tag from this using a simple regex patter like:
(img)(.*?)(([^)]+))
The above would allow me to extract the size, and url
Current Implementation Behaviour
I’ve tried using the AbstractMarkwonPlugin.processMarkdown()
function but I’m sure this is not the best way to go about this.
class CustomImagePlugin private constructor(): IMarkdownPlugin, AbstractMarkwonPlugin() {
/**
* Regular expression that should be used for the implementing class
*/
@VisibleForTesting(otherwise = Modifier.PRIVATE)
override val regex = Regex(
pattern = PATTERN_IMAGE,
option = RegexOption.IGNORE_CASE
)
override fun processMarkdown(markdown: String): String {
var buffer: String = markdown
val matchers = regex.findAll(markdown)
for (match in matchers) {
val groups = match.groups
val target = groups[GROUP_ORIGINAL_MATCH]?.value
// ... impl replacing all custom markdown spec with standarad html/mardown
}
return buffer
}
companion object {
@VisibleForTesting(otherwise = Modifier.PRIVATE)
const val PATTERN_IMAGE = "(img)(.*?)(\\([^)]+\\))"
private const val GROUP_ORIGINAL_MATCH = 0
private const val GROUP_IMAGE_SIZE = 2
private const val GROUP_IMAGE_SRC = 3
fun create() = ImagePlugin()
}
}
Could you please advise on how to go about this?
Alternative Implementation Behaviour
What I also tried was making use of AbstractMarkwonPlugin.beforeRender
but this is documented to be:
This method will be called before rendering will occur thus making possible to post-process parsed node (make changes for example).
Thus getting an image span to pick it up at this point might not work?
class CustomImagePlugin private constructor(): IMarkdownPlugin, AbstractMarkwonPlugin() {
/**
* Regular expression that should be used for the implementing class
*/
@VisibleForTesting(otherwise = Modifier.PRIVATE)
override val regex = Regex(
pattern = PATTERN_IMAGE,
option = RegexOption.IGNORE_CASE
)
override fun beforeRender(node: Node) {
node.accept(ImageVisitor())
}
inner class ImageVisitor : AbstractVisitor() {
private fun replaceLiteral(node: String): String {
var buffer: String = node
val matchers = regex.findAll(node)
for (match in matchers) {
val groups = match.groups
val target = groups[GROUP_ORIGINAL_MATCH]?.value
// ... impl replacing all custom markdown spec with standarad html/mardown
}
return buffer
}
override fun visit(text: Text?) {
val literal = text?.literal.orEmpty()
if (literal.contains(regex))
text?.literal = replaceLiteral(literal)
}
}
companion object {
@VisibleForTesting(otherwise = Modifier.PRIVATE)
const val PATTERN_IMAGE = "(img)(.*?)(\\([^)]+\\))"
private const val GROUP_ORIGINAL_MATCH = 0
private const val GROUP_IMAGE_SIZE = 2
private const val GROUP_IMAGE_SRC = 3
fun create() = ImagePlugin()
}
}
Issue Analytics
- State:
- Created 4 years ago
- Comments:6 (5 by maintainers)
Top GitHub Comments
Hello @wax911 !
I think the the
alternative
approach is the best one at the moment. It is actually advised bycommonmark
creator and used by commonmark-ext-autolink artifact (although it usescommonmark
post-processor, but it’s a minor difference).The absolute best solution would be to write a custom inline-parser, but unfortunately it’s still not possible (#113).
UPD. A small update, there is another option available since
4.0.0
:You are welcome! Feel free to re-open if you will have more questions 🙌