There are a bunch of tutorials floating around, but they seem to be incomplete or not fully current or don't fully work for me.
This is what I have done.
Gemfile:
gem 'rouge'
gem 'redcarpet'
Then I created a config/initializer/rouge.rb
:
require 'rouge/plugins/redcarpet'
Then I created a file called app/assets/stylesheets/rouge.css.erb
<%= Rouge::Themes::Github.render(:scope => '.highlight') %>
Then in my app/helpers/application_helper.rb
, I added this:
module ApplicationHelper
class HTML < Redcarpet::Render::HTML
include Rouge::Plugins::Redcarpet
def block_code(code, language)
Rouge.highlight(code, language || 'text', 'html')
end
end
def markdown(text)
render_options = {
filter_html: true,
hard_wrap: true,
link_attributes: { rel: 'nofollow' }
}
renderer = HTML.new(render_options)
extensions = {
autolink: true,
fenced_code_blocks: true,
lax_spacing: true,
no_intra_emphasis: true,
strikethrough: true,
superscript: true
}
Redcarpet::Markdown.new(renderer, extensions).render(text).html_safe
end
end
Then in my show.html.erb
, I did this:
<%= markdown(@question.body) %>
But that literally does not work. It outputs my ruby
code snippet like this:
How do I get this snippet of code to be formatted like Github? Or even just the first step being to be formatted any at all, then how do I tweak the formatting?
I don't see a stylesheet included in the source of the page, so I don't know which styles to tweak for what I want.
Edit 1
Or even when I do this:
<div class="highlight">
<%= @question.test_suite %>
</div>
It renders like this:
Edit 2
I attempted BoraMa's suggestion and I got output that looks like this:
Edit 3
I made a modification to BoraMa's answer as follows.
In my block_code
method, I call highlight as follows:
Rouge.highlight(code, 'ruby', 'html')
Then in my view I do this:
<%= raw rouge_markdown(<<-'EOF'
def rouge_me
puts "this is a #{'test'} for rouge"
end
EOF
) %>
Then that produces this:
Note I am referring to the code snippet at the bottom of the screenshot.
However, the text at the top is generated with this:
<pre class="highlight ruby">
<%= rouge_markdown(@question.body) %>
</pre>
And it is rendered as is shown in the screenshot.
Edit 4
After removing the <div class="highlight">
, I see this:
Aka....nothing is being rendered at all.
Once I add raw
to my view...aka <%= raw rouge_markdown(@question.body) %>
The view renders this:
Edit 5
Here is the content for various @question
objects:
[1] pry(#<#<Class:0x007fc041b97ce8>>)> @question.body
=> "5.times do\r\n puts \"Herro Rerl!\"\r\nend"
[1] pry(#<#<Class:0x007fc041b97ce8>>)> @question.body
=> "puts \"Hello World version 9\"\r\nputs \"This comes after version 8.\"\r\nputs \"This comes after version 7.\"\r\nputs \"This comes after version 6.\"\r\nputs \"This comes after version 5.\"\r\nputs \"This comes after version 4.\"\r\nputs \"This comes after version 3.\"\r\nputs \"This comes after version 2.\"\r\nputs \"This definitely comes after version 1.\""
[1] pry(#<#<Class:0x007fc041b97ce8>>)> @question.body
=> "def convert_relation(invited_gender, relation)\r\n case invited_gender\r\n \twhen \"male\"\r\n \tcase relation\r\n when \"daughter\", \"son\" then \"dad\"\r\n when \"mom\", \"dad\" then \"son\"\r\n when \"grandfather\", \"grandmother\" then \"grandson\"\r\n when \"sister\", \"brother\" then \"brother\"\r\n when \"wife\" then \"husband\"\r\n when \"husband\" then \"husband\"\r\n end\r\n when \"female\"\r\n \tcase relation\r\n when \"daughter\", \"son\" then \"mom\"\r\n when \"mom\", \"dad\" then \"daughter\"\r\n when \"grandfather\", \"grandmother\" then \"granddaughter\"\r\n when \"sister\", \"brother\" then \"sister\"\r\n when \"wife\" then \"wife\"\r\n when \"husband\" then \"wife\"\r\n end\r\n end\r\nend\r\n\r\nputs convert_relation(\"male\", \"wife\")"
To add a syntax highlighting language, simply check its checkbox in the main list of languages. It will appear with a checkmark in bold font to show that it has been selected but not yet installed.
Syntax highlighting determines the color and style of source code displayed in the Visual Studio Code editor. It is responsible for colorizing keywords like if or for in JavaScript differently than strings and comments and variable names.
The original question indicated (in the solution attempted) that markdown would be used in the highlighted questions but it turned out not to be the case. So this answer is split to two distinct sections, one for highlighting pure code without markdown, the other one for markdown text with code.
In this case, and according to the README, all you need to highlight the code with Rouge is a lexer and a formatter. Since the highlighted text will be displayed on a web page, you need the HTML formatter. For the lexer, you need to know the language the code is in beforehand (or you may try guessing it from the source code itself but it does not seem to be very reliable for small code snippets).
You can create a simple helper method for the highlighting:
module RougeHelper
def rouge(text, language)
formatter = Rouge::Formatters::HTML.new(css_class: 'highlight')
lexer = Rouge::Lexer.find(language)
formatter.format(lexer.lex(text))
end
end
Then in the template, simply call this helper with a text to highlight and the language:
<%= raw rouge("def rouge_me\n puts 'hey!'\nend", "ruby") %>
Which will render:
To get a list of all languages that Rouge supports and their corresponding names that should be passed to the rouge
helper, you can use the following code. The code gets all defined lexers from Rouge and shows their tags (i.e. the names Rouge recognizes them with):
Rouge::Lexer.all.map(&:tag).sort
# => ["actionscript", "apache", "apiblueprint", "applescript", ..., "xml", "yaml"]
You can (and probably should) use this list when showing users the languages to choose from in the selection box. Note that each lexer also has the title
and desc
methods defined that will give you a human-readable name and a short description of each of them. You might want to use this info to be shown to the user, too.
Note: you should get rid of the initializer, the custom HTML class and the div
wrapped around the rouge helper call (all of these you have in your original attempt). The only thing you need besides the code above is the CSS rules, which you have already correctly included in the web page.
A couple of changes from your attempt to make it work:
The initializer is not needed, you can remove it I think (but if you don't want to require
all the files later in the helper, I guess you can leave it).
Remove the block_code
method from the helper class, the same is already done by including the markdown plugin.
Remove the <div class="highlight">
wrapper div from your template and just use the helper in it. Rouge adds its own wrapper with the "highlight" class and another div seems to confuse it.
Try the following helper code. BTW, I moved the code from ApplicationHelper
to a separate RougeHelper
(but that is not a required change):
module RougeHelper
require 'redcarpet'
require 'rouge'
require 'rouge/plugins/redcarpet'
class HTML < Redcarpet::Render::HTML
include Rouge::Plugins::Redcarpet
end
def rouge_markdown(text)
render_options = {
filter_html: true,
hard_wrap: true,
link_attributes: { rel: 'nofollow' }
}
renderer = HTML.new(render_options)
extensions = {
autolink: true,
fenced_code_blocks: true,
lax_spacing: true,
no_intra_emphasis: true,
strikethrough: true,
superscript: true
}
markdown = Redcarpet::Markdown.new(renderer, extensions)
markdown.render(text)
end
end
Then, in the template, I tried to highlight a test ruby code:
<%= raw rouge_markdown(<<-'EOF'
```ruby
def rouge_me
puts "this is a #{'test'} for rouge"
end
```
EOF
) %>
Note that I needed to specify the language manually, which made me use the 3 backticks way to delimit the code instead of space indentation. I have no clue why the code language autodetection did not work here, perhaps it's a too short code.
In the end this rendered the colors for me nicely:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With