Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interpret newlines as <br>s in markdown (Github Markdown-style) in Ruby

I'm using markdown for comments on my site and I want users to be able to create line breaks by pressing enter instead of space space enter (see this meta question for more details on this idea)

How can I do this in Ruby? You'd think Github Flavored Markdown would be exactly what I need, but (surprisingly), it's quite buggy.

Here's their implementation:

# in very clear cases, let newlines become <br /> tags
text.gsub!(/^[\w\<][^\n]*\n+/) do |x|
  x =~ /\n{2}/ ? x : (x.strip!; x << "  \n")
end

This logic requires that the line start with a \w for a linebreak at the end to create a <br>. The reason for this requirement is that you don't to mess with lists: (But see the edit below; I'm not even sure this makes sense)

* we don't want a <br>
* between these two list items

However, the logic breaks in these cases:

[some](http://google.com)
[links](http://google.com)
*this line is in italics*
another line
> the start of a blockquote!
another line

I.e., in all of these cases there should be a <br> at the end of the first line, and yet GFM doesn't add one

Oddly, this works correctly in the javascript version of GFM.

Does anyone have a working implementation of "new lines to <br>s" in Ruby?

Edit: It gets even more confusing!

If you check out Github's official Github Flavored Markdown repository, you'll find yet another newline to <br> regex!:

# in very clear cases, let newlines become <br /> tags
text.gsub!(/(\A|^$\n)(^\w[^\n]*\n)(^\w[^\n]*$)+/m) do |x|
  x.gsub(/^(.+)$/, "\\1  ")
end

I have no clue what this regex means, but it doesn't do any better on the above test cases.

Also, it doesn't look like the "don't mess with lists" justification for requiring that lines start with word characters is valid to begin with. I.e., standard markdown list semantics don't change regardless of whether you add 2 trailing spaces. Here:

  • item 1
  • item 2
  • item 3

In the source of this question there are 2 trailing spaces after "item 1", and yet if you look at the HTML, there is no superfluous <br>

This leads me to think the best regex for converting newlines to <br>s is just:

text.gsub!(/^[^\n]+\n+/) do |x|
  x =~ /\n{2}/ ? x : (x.strip!; x << "  \n")
end

Thoughts?

like image 731
Tom Lehman Avatar asked Nov 20 '10 00:11

Tom Lehman


People also ask

How do you insert a line break in Markdown?

Line Breaks To create a line break or new line ( <br> ), end a line with two or more spaces, and then type return.

What is GitHub Markdown syntax?

Markdown coverts text with four leading spaces into a code block; with GFM you can wrap your code with ``` to create a code block without the leading spaces. Add an optional language identifier and your code with get syntax highlighting. EMOJI. To see a list of every image we support, check out. www.emoji-cheat-sheet. ...

What are GitHub Markdown elements?

Markdown allows users to format text using bold and italic styles and create headers, lists, and links. The toolbar on GitHub takes this further and includes specific features like task lists, links to issues and pull requests, and handy @ mentions.


2 Answers

I'm not sure if this will help, but I just use simple_format() from ActionView::Helpers::TextHelper

ActionView simple_format

my_text = "Here is some basic text...\n...with a line break."

simple_format(my_text)

output => "<p>Here is some basic text...\n<br />...with a line break.</p>"

Even if it doesn't meet your specs, looking at the simple_format() source code .gsub! methods might help you out writing your own version of required markdown.

like image 94
David Barlow Avatar answered Sep 24 '22 22:09

David Barlow


A little too late, but perhaps useful for other people. I've gotten it to work (but not thoroughly tested) by preprocessing the text using regular expressions, like so. It's hideous as a result of the lack of zero-width lookbehinds, but oh well.

# Append two spaces to a simple line, if it ends in newline, to render the
# markdown properly. Note: do not do this for lists, instead insert two newlines. Also, leave double newlines
# alone.
text.gsub! /^ ([\*\+\-]\s+|\d+\s+)? (.+?) (\ \ )? \r?\n (\r?\n|[\*\+\-]\s+|\d+\s+)? /xi do
  full, pre, line, spaces, post = $~.to_a
  if post != "\n" && pre.blank? && post.blank? && spaces.blank?
    "#{pre}#{line}  \n#{post}"
  elsif pre.present? || post.present?
    "#{pre}#{line}\n\n#{post}"
  else
    full
  end
end
like image 45
Yoazt Avatar answered Sep 22 '22 22:09

Yoazt