vmg / redcarpet

The safe Markdown parser, reloaded.
MIT License
4.99k stars 527 forks source link

What's the best way to define your own header method? #638

Open jfly opened 6 years ago

jfly commented 6 years ago

I followed the instructions here to implement my own header method. I want to generate headers with a pretty anchor link so users can easily link to parts of my markdown document. Something like this:

image

(I'm setting with_toc_data to true so I can also generate a table of contents)

When overriding the header method, I need to include an id attribute in the generated <h1> tag. I want that id to match the links that will be generated by Redcarpet::Render::HTML_TOC, so I need to hook into the rndr_header_anchor (called by the rndr_header method which I'm trying to override). I couldn't find any way to call the rndr_header_anchor method myself from Ruby, so I've resorted to this hack:

# This is annoying. Redcarpet implements this id generation logic in C, and
# AFAIK doesn't provide any hook for calling this method directly from Ruby.
# See C code here: https://github.com/vmg/redcarpet/blob/f441dec42a5097530328b20e9d5ed1a025c600f7/ext/redcarpet/html.c#L273-L319
def header_anchor(text)
  Nokogiri::HTML(Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(with_toc_data: true)).render("# #{text}")).css('h1')[0]["id"]
end

def header(text, header_level)
  if @options[:with_toc_data]
    id = header_anchor(text)
    text = anchorable(text, id)
  end

  "<h#{header_level}>#{text}</h#{header_level}>\n"
end

Is there a better way to achieve what I'm trying to do here?

nikolalsvk commented 6 years ago

Hey @jfly, thanks for posting this hack. I'm just interested in what does anchorable do?

jfly commented 6 years ago

@nikolalsvk, I'm glad you found this helpful! Here's the definition of our anchorable.