Question

Is there a way to use either Redcarpet or Bluecloth such that when it interpolates the markdown it won't make any headers?

For example:

#header 1

yields:

header 1

header 1 (preferred)

And:

##header 2

yields:

header 2

header 2 (preferred)

Was it helpful?

Solution

Well, you can escape characters in Markdown:

# header 1
\# header 1

## header 2
\## header 2

...gives:

header 1

# header 1

header 2

## header 2

If you don't want to have to do this, or you're parsing other people's Markdown and don't have a choice, I would recommend pre-processing the incoming Markdown to do the above for you:

def pound_filter text
  text.gsub /^#/, '\#'
end

Using Redcarpet you can verify that it works:

text = <<-END
  # Hello
  ## World
END

Markdown.new(text.to_html)
# =>  <h1>Hello</h1>
#
#     <h2>World</h2>

Markdown.new(pound_filter text).to_html
# =>  <p># Hello
#     ## World</p>

Of course since a line break in HTML doesn't actually render as such--it will appear as one line:

# Hello ## World"

...you might want to augment that:

def pound_filter text
  text.gsub( /((\A^)|([^\A]^))#/ ) {|match| "\n" == match[0] ? "\n\n\\#" : '\#' }
end

pound_filter text
# =>  \# Hello
#
#     \## World

Markdown.new(pound_filter text).to_html
# =>  <p>\# Hello</p>
#
#     <p>\## World</p>

This last would appear as:

# Hello

## World

Unfortunately you eventually get into weird territory like this, where a heading is inside a quote:

> ## Heading

...but I leave that as an exercise to the reader.

OTHER TIPS

Saw a similar solution here that went like this:

class RenderWithoutWrap < Redcarpet::Render::HTML
  def postprocess(full_document)
    Regexp.new(/\A<p>(.*)<\/p>\Z/m).match(full_document)[1] rescue full_document
  end
end

It removes all <p> & </p> tags. I used it like that and it worked. I placed that class in a new file called /config/initializers/render_without_wrap.rb. You could do something similar for all <h1>-<h6> tags

class RenderWithoutHeaders < Redcarpet::Render::HTML
  def postprocess(full_document)
    Regexp.new(/\A<h1>(.*)<\/h1>\Z/m).match(full_document)[1] rescue full_document
    Regexp.new(/\A<h2>(.*)<\/h2>\Z/m).match(full_document)[1] rescue full_document
    Regexp.new(/\A<h3>(.*)<\/h3>\Z/m).match(full_document)[1] rescue full_document
    ...(you get the idea)
  end
end

You could then use it like this

def custom_markdown_parse(text)
  markdown = Redcarpet::Markdown.new(RenderWithoutHeaders.new(
    filter_html: true,
    hard_wrap: true,
    other_options: its_your_call
  ))
  markdown.render(text).html_safe
end

I haven't tested it, but it's an idea.

1. You should be able to escape your markdown source text with backslashes:

\# not a header

2. You could also monkey-patch it:

module RedCloth::Formatters::HTML

  [:h1, :h2, :h3, :h4, :h5, :h6].each do |m|
    define_method(m) do |opts|
      "#{opts[:text]}\n"
    end
  end

end

Given that twiddling the Markdown pre-parsing is hard, and Markdown allows inserted HTML, how about stripping out heading elements from the resulting HTML instead?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top