如何在 Rails 中实现 Rouge 语法高亮显示?
How do I implement Rouge syntax highlighting in Rails?
周围有很多教程,但它们似乎不完整或不是最新的或者不完全适合我。
这就是我所做的。
宝石文件:
gem 'rouge'
gem 'redcarpet'
然后我创建了一个config/initializer/rouge.rb
:
require 'rouge/plugins/redcarpet'
然后我创建了一个名为 app/assets/stylesheets/rouge.css.erb
的文件
<%= Rouge::Themes::Github.render(:scope => '.highlight') %>
然后在我的 app/helpers/application_helper.rb
中,我添加了这个:
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
然后在我的 show.html.erb
中,我这样做了:
<%= markdown(@question.body) %>
但这实际上是行不通的。它输出我的 ruby
代码片段,如下所示:
如何将这段代码格式化为 Github?或者甚至只是第一步要格式化,那么我该如何调整格式?
我没有在页面源代码中看到样式表,所以我不知道要根据需要调整哪些样式。
编辑 1
甚至当我这样做时:
<div class="highlight">
<%= @question.test_suite %>
</div>
它呈现如下:
编辑 2
我尝试了 BoraMa 的建议,得到的输出如下所示:
编辑 3
我对BoraMa的回答做了如下修改
在我的 block_code
方法中,我调用高亮显示如下:
Rouge.highlight(code, 'ruby', 'html')
然后在我看来我这样做:
<%= raw rouge_markdown(<<-'EOF'
def rouge_me
puts "this is a #{'test'} for rouge"
end
EOF
) %>
然后产生这个:
请注意,我指的是屏幕截图底部的代码片段。
但是,顶部的文本是这样生成的:
<pre class="highlight ruby">
<%= rouge_markdown(@question.body) %>
</pre>
它被渲染为截图所示。
编辑 4
删除 <div class="highlight">
后,我看到了这个:
Aka....根本没有渲染任何内容。
一旦我将 raw
添加到我的视图中...又名 <%= raw rouge_markdown(@question.body) %>
视图呈现如下:
编辑 5
这里是各种 @question
对象的内容:
[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\")"
原始问题表明(在尝试的解决方案中)标记将用于突出显示的问题,但事实并非如此。所以这个答案分为两个不同的部分,一个用于突出显示没有降价的纯代码,另一个用于带有代码的降价文本。
A) 你想突出显示纯代码(不涉及 Markdown)
在这种情况下,并根据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。对于词法分析器,你需要事先知道代码使用的语言(或者你可以尝试从源代码本身猜测它,但对于小代码片段它似乎不太可靠)。
您可以为突出显示创建一个简单的辅助方法:
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
然后在模板中,只需使用要突出显示的文本和语言调用此助手:
<%= raw rouge("def rouge_me\n puts 'hey!'\nend", "ruby") %>
将呈现:
要获取 Rouge 支持的所有语言的列表 及其应传递给 rouge
助手的相应名称,您可以使用以下代码。该代码从 Rouge 获取所有定义的词法分析器并显示它们的 标签(即 Rouge 识别它们的名称):
Rouge::Lexer.all.map(&:tag).sort
# => ["actionscript", "apache", "apiblueprint", "applescript", ..., "xml", "yaml"]
在向用户显示选择框中可供选择的语言时,您可以(并且可能应该)使用此列表。请注意,每个词法分析器还定义了 title
和 desc
方法,它们将为您提供 human-readable 名称和每个方法的简短描述。您可能也希望使用此信息向用户显示。
注意:你应该去掉初始化器,自定义 HTML class 和围绕 rouge helper 调用的 div
(所有这些你在你最初的尝试中都有)。除了上面的代码之外,您唯一需要的是 CSS 规则,您已经将其正确包含在网页中。
B) 突出显示的文本是带有代码块的 Markdown 文本
从您尝试使其工作的几个变化:
不需要初始化程序,我想你可以删除它(但如果你不想 require
稍后在助手中的所有文件,我想你可以保留它).
从 helper class 中删除 block_code
方法,通过包含 markdown 插件已经完成了同样的操作。
从您的模板中删除 <div class="highlight">
包装器 div 并只使用其中的助手。 Rouge 用 "highlight" class 添加了自己的包装器,另一个 div 似乎混淆了它。
试试下面的帮助代码。顺便说一句,我将代码从 ApplicationHelper
移到了单独的 RougeHelper
(但这不是必需的更改):
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
然后,在模板中,我尝试突出显示测试 ruby 代码:
<%= raw rouge_markdown(<<-'EOF'
```ruby
def rouge_me
puts "this is a #{'test'} for rouge"
end
```
EOF
) %>
请注意,我需要手动指定语言,这使我使用 3 个反引号的方式来分隔代码而不是 space 缩进。我不知道为什么代码语言自动检测在这里不起作用,也许是代码太短了。
最后这对我来说很好地渲染了颜色:
周围有很多教程,但它们似乎不完整或不是最新的或者不完全适合我。
这就是我所做的。
宝石文件:
gem 'rouge'
gem 'redcarpet'
然后我创建了一个config/initializer/rouge.rb
:
require 'rouge/plugins/redcarpet'
然后我创建了一个名为 app/assets/stylesheets/rouge.css.erb
<%= Rouge::Themes::Github.render(:scope => '.highlight') %>
然后在我的 app/helpers/application_helper.rb
中,我添加了这个:
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
然后在我的 show.html.erb
中,我这样做了:
<%= markdown(@question.body) %>
但这实际上是行不通的。它输出我的 ruby
代码片段,如下所示:
如何将这段代码格式化为 Github?或者甚至只是第一步要格式化,那么我该如何调整格式?
我没有在页面源代码中看到样式表,所以我不知道要根据需要调整哪些样式。
编辑 1
甚至当我这样做时:
<div class="highlight">
<%= @question.test_suite %>
</div>
它呈现如下:
编辑 2
我尝试了 BoraMa 的建议,得到的输出如下所示:
编辑 3
我对BoraMa的回答做了如下修改
在我的 block_code
方法中,我调用高亮显示如下:
Rouge.highlight(code, 'ruby', 'html')
然后在我看来我这样做:
<%= raw rouge_markdown(<<-'EOF'
def rouge_me
puts "this is a #{'test'} for rouge"
end
EOF
) %>
然后产生这个:
请注意,我指的是屏幕截图底部的代码片段。
但是,顶部的文本是这样生成的:
<pre class="highlight ruby">
<%= rouge_markdown(@question.body) %>
</pre>
它被渲染为截图所示。
编辑 4
删除 <div class="highlight">
后,我看到了这个:
Aka....根本没有渲染任何内容。
一旦我将 raw
添加到我的视图中...又名 <%= raw rouge_markdown(@question.body) %>
视图呈现如下:
编辑 5
这里是各种 @question
对象的内容:
[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\")"
原始问题表明(在尝试的解决方案中)标记将用于突出显示的问题,但事实并非如此。所以这个答案分为两个不同的部分,一个用于突出显示没有降价的纯代码,另一个用于带有代码的降价文本。
A) 你想突出显示纯代码(不涉及 Markdown)
在这种情况下,并根据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。对于词法分析器,你需要事先知道代码使用的语言(或者你可以尝试从源代码本身猜测它,但对于小代码片段它似乎不太可靠)。
您可以为突出显示创建一个简单的辅助方法:
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
然后在模板中,只需使用要突出显示的文本和语言调用此助手:
<%= raw rouge("def rouge_me\n puts 'hey!'\nend", "ruby") %>
将呈现:
要获取 Rouge 支持的所有语言的列表 及其应传递给 rouge
助手的相应名称,您可以使用以下代码。该代码从 Rouge 获取所有定义的词法分析器并显示它们的 标签(即 Rouge 识别它们的名称):
Rouge::Lexer.all.map(&:tag).sort
# => ["actionscript", "apache", "apiblueprint", "applescript", ..., "xml", "yaml"]
在向用户显示选择框中可供选择的语言时,您可以(并且可能应该)使用此列表。请注意,每个词法分析器还定义了 title
和 desc
方法,它们将为您提供 human-readable 名称和每个方法的简短描述。您可能也希望使用此信息向用户显示。
注意:你应该去掉初始化器,自定义 HTML class 和围绕 rouge helper 调用的 div
(所有这些你在你最初的尝试中都有)。除了上面的代码之外,您唯一需要的是 CSS 规则,您已经将其正确包含在网页中。
B) 突出显示的文本是带有代码块的 Markdown 文本
从您尝试使其工作的几个变化:
不需要初始化程序,我想你可以删除它(但如果你不想
require
稍后在助手中的所有文件,我想你可以保留它).从 helper class 中删除
block_code
方法,通过包含 markdown 插件已经完成了同样的操作。从您的模板中删除
<div class="highlight">
包装器 div 并只使用其中的助手。 Rouge 用 "highlight" class 添加了自己的包装器,另一个 div 似乎混淆了它。
试试下面的帮助代码。顺便说一句,我将代码从 ApplicationHelper
移到了单独的 RougeHelper
(但这不是必需的更改):
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
然后,在模板中,我尝试突出显示测试 ruby 代码:
<%= raw rouge_markdown(<<-'EOF'
```ruby
def rouge_me
puts "this is a #{'test'} for rouge"
end
```
EOF
) %>
请注意,我需要手动指定语言,这使我使用 3 个反引号的方式来分隔代码而不是 space 缩进。我不知道为什么代码语言自动检测在这里不起作用,也许是代码太短了。
最后这对我来说很好地渲染了颜色: