summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMunken <mm.munk@gmail.com>2016-12-09 00:15:08 +0000
committerMunken <mm.munk@gmail.com>2016-12-14 16:50:54 +0000
commit2d170a20dc4cd3423ac7994c797cae8fbed263ba (patch)
tree273aeac77c48c027600afb2da40eee739dd6872e /lib
parente3f5c4c5f66c42ebf3c25c4d23507b56843b006d (diff)
downloadgitlab-ce-2d170a20dc4cd3423ac7994c797cae8fbed263ba.tar.gz
Render math in Asciidoc and Markdown with KaTeX using code blocks
Diffstat (limited to 'lib')
-rw-r--r--lib/banzai/filter/inline_math_filter.rb27
-rw-r--r--lib/banzai/filter/math_filter.rb51
-rw-r--r--lib/banzai/filter/syntax_highlight_filter.rb3
-rw-r--r--lib/banzai/pipeline/gfm_pipeline.rb2
-rw-r--r--lib/gitlab/asciidoc.rb31
-rw-r--r--lib/gitlab/gon_helper.rb2
-rw-r--r--lib/rouge/lexers/math.rb6
7 files changed, 87 insertions, 35 deletions
diff --git a/lib/banzai/filter/inline_math_filter.rb b/lib/banzai/filter/inline_math_filter.rb
deleted file mode 100644
index 1bbe602237a..00000000000
--- a/lib/banzai/filter/inline_math_filter.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require 'uri'
-
-module Banzai
- module Filter
- # HTML filter that adds class="code math" and removes the dolar sign in $`2+2`$.
- #
- class InlineMathFilter < HTML::Pipeline::Filter
- def call
- doc.xpath("descendant-or-self::text()[substring(., string-length(.)) = '$']"\
- "/following-sibling::*[name() = 'code']"\
- "/following-sibling::text()[starts-with(.,'$')]").each do |el|
- closing = el
- code = el.previous
- code[:class] = 'code math'
- opening = code.previous
-
- closing.content = closing.content[1..-1]
- opening.content = opening.content[0..-2]
-
- closing
- end
-
- doc
- end
- end
- end
-end
diff --git a/lib/banzai/filter/math_filter.rb b/lib/banzai/filter/math_filter.rb
new file mode 100644
index 00000000000..cb037f89337
--- /dev/null
+++ b/lib/banzai/filter/math_filter.rb
@@ -0,0 +1,51 @@
+require 'uri'
+
+module Banzai
+ module Filter
+ # HTML filter that adds class="code math" and removes the dollar sign in $`2+2`$.
+ #
+ class MathFilter < HTML::Pipeline::Filter
+ # This picks out <code>...</code>.
+ INLINE_MATH = 'descendant-or-self::code'.freeze
+
+ # Pick out a code block which is declared math
+ DISPLAY_MATH = "descendant-or-self::pre[contains(@class, 'math') and contains(@class, 'code')]".freeze
+
+ # Attribute indicating inline or display math.
+ STYLE_ATTRIBUTE = 'data-math-style'.freeze
+
+ # Class used for tagging elements that should be rendered
+ TAG_CLASS = 'js-render-math'.freeze
+
+ INLINE_CLASSES = "code math #{TAG_CLASS}".freeze
+
+ DOLLAR_SIGN = '$'.freeze
+
+ def call
+ doc.xpath(INLINE_MATH).each do |code|
+ closing = code.next
+ opening = code.previous
+
+ # We need a sibling before and after.
+ # They should end and start with $ respectively.
+ if closing && opening &&
+ closing.content.first == DOLLAR_SIGN &&
+ opening.content.last == DOLLAR_SIGN
+
+ code[:class] = INLINE_CLASSES
+ code[STYLE_ATTRIBUTE] = 'inline'
+ closing.content = closing.content[1..-1]
+ opening.content = opening.content[0..-2]
+ end
+ end
+
+ doc.xpath(DISPLAY_MATH).each do |el|
+ el[STYLE_ATTRIBUTE] = 'display'
+ el[:class] += " #{TAG_CLASS}"
+ end
+
+ doc
+ end
+ end
+ end
+end
diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb
index e7f6b715ba8..026b81ac175 100644
--- a/lib/banzai/filter/syntax_highlight_filter.rb
+++ b/lib/banzai/filter/syntax_highlight_filter.rb
@@ -48,9 +48,6 @@ module Banzai
end
def lexer_for(language)
- if language == 'math'
- return Rouge::Lexers::Math.new
- end
(Rouge::Lexer.find(language) || Rouge::Lexers::PlainText).new
end
diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb
index 2c81cbe56b3..5a1f873496c 100644
--- a/lib/banzai/pipeline/gfm_pipeline.rb
+++ b/lib/banzai/pipeline/gfm_pipeline.rb
@@ -6,7 +6,7 @@ module Banzai
Filter::SyntaxHighlightFilter,
Filter::SanitizationFilter,
- Filter::InlineMathFilter,
+ Filter::MathFilter,
Filter::UploadLinkFilter,
Filter::VideoLinkFilter,
Filter::ImageLinkFilter,
diff --git a/lib/gitlab/asciidoc.rb b/lib/gitlab/asciidoc.rb
index 9667df4ffb8..f77f412da56 100644
--- a/lib/gitlab/asciidoc.rb
+++ b/lib/gitlab/asciidoc.rb
@@ -1,4 +1,5 @@
require 'asciidoctor'
+require 'asciidoctor/converter/html5'
module Gitlab
# Parser/renderer for the AsciiDoc format that uses Asciidoctor and filters
@@ -23,7 +24,7 @@ module Gitlab
def self.render(input, context, asciidoc_opts = {})
asciidoc_opts.reverse_merge!(
safe: :secure,
- backend: :html5,
+ backend: :gitlab_html5,
attributes: []
)
asciidoc_opts[:attributes].unshift(*DEFAULT_ADOC_ATTRS)
@@ -36,3 +37,31 @@ module Gitlab
end
end
end
+
+module Gitlab
+ module Asciidoc
+ class Html5Converter < Asciidoctor::Converter::Html5Converter
+ extend Asciidoctor::Converter::Config
+
+ register_for 'gitlab_html5'
+
+ def stem(node)
+ return super unless node.style.to_sym == :latexmath
+
+ %(<pre#{id_attribute(node)} class="code math js-render-math #{node.role}" data-math-style="display"><code>#{node.content}</code></pre>)
+ end
+
+ def inline_quoted(node)
+ return super unless node.type.to_sym == :latexmath
+
+ %(<code#{id_attribute(node)} class="code math js-render-math #{node.role}" data-math-style="inline">#{node.text}</code>)
+ end
+
+ private
+
+ def id_attribute(node)
+ node.id ? %( id="#{node.id}") : nil
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 2c21804fe7a..4d4e04e9e35 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -8,6 +8,8 @@ module Gitlab
gon.shortcuts_path = help_page_path('shortcuts')
gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class
gon.award_menu_url = emojis_path
+ gon.katex_css_url = ActionController::Base.helpers.asset_path('katex.css')
+ gon.katex_js_url = ActionController::Base.helpers.asset_path('katex.js')
if current_user
gon.current_user_id = current_user.id
diff --git a/lib/rouge/lexers/math.rb b/lib/rouge/lexers/math.rb
index ae980da8283..80784adfd76 100644
--- a/lib/rouge/lexers/math.rb
+++ b/lib/rouge/lexers/math.rb
@@ -1,13 +1,13 @@
module Rouge
module Lexers
class Math < Lexer
- title "Plain Text"
+ title "A passthrough lexer used for LaTeX input"
desc "A boring lexer that doesn't highlight anything"
tag 'math'
mimetypes 'text/plain'
- default_options :token => 'Text'
+ default_options token: 'Text'
def token
@token ||= Token[option :token]
@@ -18,4 +18,4 @@ module Rouge
end
end
end
-end \ No newline at end of file
+end