comrak icon indicating copy to clipboard operation
comrak copied to clipboard

Extention request: Support arbitrary attributes

Open doits opened this issue 5 months ago • 12 comments

I would be nice if it would support adding arbitrary attributes to block and inline elements, e.g.:

> A nice blockquote
{: title="Blockquote title"}

==>

<blockquote title="Blockquote title">
<p>A nice blockquote</p>
</blockquote>

A PHP parser has this available like this: https://commonmark.thephpleague.com/2.4/extensions/attributes/

Kramdown supports this like this: https://kramdown.gettalong.org/quickref.html#block-attributes and https://kramdown.gettalong.org/quickref.html#inline-attributes

doits avatar Aug 04 '25 12:08 doits

Hiya! It would be nice. I'd accept a PR that implemented this as an option!

kivikakk avatar Aug 05 '25 02:08 kivikakk

I agree, this would be great to have built-in. I did a very minimal implementation in Ruby for images/videos, but it's a hack, handled after the fact.

I tend to favor John MacFarlane's implementations (such as Pandoc), and he has a Haskell implementation of this. What I like is that he's already got a spec/tests. So that's the syntax I was working towards. Since he's the creator of CommonMark, and Pandoc, I always feel there is more thought put into the syntax and implementation. But that's a biased opinion.

digitalmoksha avatar Aug 05 '25 17:08 digitalmoksha

Thanks for your fast replies!

MacFarlane's implentetion looks good. Only difference I'd prefer is that custom attributes besides data-* can be set. If I read the specs correctly it looks like every key=value gets translated to <... data-key="value">, which prevents setting stuff like title etc.

For the implementation I don't think I can be of much help though since I never touched Rust before. And a quick glance at the source code of the autolink extension does not make me think implenteting a custom attribute extension would be a good start with Rust for me :-)

doits avatar Aug 05 '25 19:08 doits

Setting any normal HTML attributes is possible. I have it running locally:

> cabal run exes -- -x attributes

![](foo.jpg){title="test" width="30px" extra="bar"}

<p><img title="test" width="30px" data-extra="bar" src="foo.jpg" alt="" /></p>

digitalmoksha avatar Aug 05 '25 20:08 digitalmoksha

Mm! And assuming we have a way to nicely parse them into the AST, one could use a custom formatter to choose how they're presented on any given tag.

kivikakk avatar Aug 06 '25 02:08 kivikakk

Exactly - a set of reasonable rules in the default formatter, which can be overridden when necessary.

digitalmoksha avatar Aug 06 '25 14:08 digitalmoksha

Setting any normal HTML attributes is possible. I have it running locally:

Thanks for the info, looks like the examples in the spec are slightly wrong then.

Edit: Ahh I see now, it comes from the fact that custom attributes automatically get the data-prefix, see https://github.com/jgm/commonmark-hs/commit/4f7d8b7b37dcc672d46f6bf967afbd47c589e050. OK, that is the reason, though not sure if one should really follow this logic 🤔

doits avatar Aug 06 '25 15:08 doits

I've seen this syntax also extended to support css classes like:

[a link]("../some/link"){.myclass width="100%"}

Both of these are extremely useful imho.

edit

https://github.com/druskus20/comrak/tree/link_properties

I took a crack at it with links and images. It's not ready for PR, the code is somewhat dirty and it's not an optional extension yet. However it passes all tests (cargo test). I had to use html_opts_i with roundtrip disabled for the tests I added though.

https://github.com/druskus20/comrak/blob/link_properties/src/tests/link_attributes.rs

of course this is me experimenting on my own, without previous discussion of the syntax etc. It's not completely comformant with the spec yet, for example it doesnt support multiple classes as it stands, but making it spec compliant should be easy. I am unsure how this could be implemented in a more general way for other elements such as headings - with the current parser

druskus20 avatar Nov 05 '25 00:11 druskus20

Hi! If you'd like to open a PR for me to have a look, please feel free <3

I had to use html_opts_i with roundtrip disabled for the tests I added though.

You can pass an extra no_roundtrip argument to html_opts!, btw :) if you search for no_roundtrip you'll see some example usages.

kivikakk avatar Nov 10 '25 03:11 kivikakk

I'm okay with opening a PR - I should clean up the code a bit - lets see if I have a bit of time this week.

However, I am curious about how to implement this for any kind of markdown element, in a more generalized way, like the spec says - as I mentioned, right now it's only implemented for links and images.

Of course I can still open a PR for this and you can decide if it's worth by itself or not

druskus20 avatar Nov 10 '25 04:11 druskus20

It'd be quite a bit of work! I haven't looked at your current implementation in detail (though I have peeked at it); we'd have to look for potential attributes everywhere, which I think would be pretty rough for some elements, particularly block elements.

I think the best cleanup you could do right now is to use an re2c scanner to parse the properties themselves; see src/scanners.re for existing ones. That'd help remove a lot of the very manual and error-prone scanning in parse_link_properties. Otherwise the changes look really clean, and I like the LinkProperty enum a lot!

kivikakk avatar Nov 10 '25 04:11 kivikakk

Yeah, probably some renaming to do too, I did not think much about terminology I just wanted to see if it would work 👍

druskus20 avatar Nov 10 '25 05:11 druskus20