Open MateuszKubuszok opened 5 years ago
Thanks for reporting this issue.
As a temporary workaround, I think you might have to close the katexmm
environment when you have code blocks with $
.
I'd have to think about this for a bit. I'm not sure how easy it would be to detect all the different situations where this might be impacted (e.g., fenced code blocks) and it's not obvious to me at this time what the right strategy would be for ignoring unmatched $
since there can be many possible endings/openings.
Currently, the matching strategy is to select first matching delimiter ($
/$$
). If there are many math blocks, it's unclear how to reliably determine which $
/$$
is unclosed since it will likely detect any following $
as the close. Doing a first pass to match everything up can be dicey since it's not obvious how I can tell if contents within a block was intended or not.
Suggestions for how to gracefully handle this situation would be appreciated. I am currently considering the following:
$
in blocksI had a workaround I tried (before switching to katex math engine in kramdown) was declaring a fixed tag as a Jekyll plugin:
# frozen_string_literal: true
require 'jekyll'
require 'jekyll-katex/configuration'
require 'jekyll-katex/katex_js'
require 'nokogiri'
module Jekyll
module Tags
# Defines the custom Liquid tag for compile-time rendering of KaTeX math.
# This differs from the katex tag in that it allows use of `$` and `$$` fencing to mark math mode blocks similar to
# standard latex.
# {% katexmm %}
# This is a mixed environment where you can write text as normal but fence off latex math using `$`. Escape
# using `\$`. For example.
# $latex math with \$$
# $$display mode latex$$
# {% endkatexmm %}
class KatexMathModeFixed < Liquid::Block
LOG_TOPIC = 'KatexMathModeFixed:'
KATEX ||= Jekyll::Katex::KATEX_JS
LATEX_TOKEN_PATTERN = /(?<!\\)([$]{2}|[$]{1})(.+?)(?<!\\)\1/m
def initialize(tag_name, markup, tokens)
super
@markup = markup
@tokens = tokens
@display_mode_rendering = Jekyll::Katex::Configuration.global_rendering_options.merge(displayMode: true)
@inline_mode_rendering = Jekyll::Katex::Configuration.global_rendering_options.merge(displayMode: false)
end
def render(context)
enclosed_block = super
fixed_block = fix_code(enclosed_block)
rendered_str = fixed_block.to_s.gsub(LATEX_TOKEN_PATTERN) do |match|
display_mode = match.to_s.start_with? '$$'
rendering_options = display_mode ? @display_mode_rendering : @inline_mode_rendering
Jekyll.logger.debug LOG_TOPIC, "Rendering matched block - #{match}"
KATEX.call('katex.renderToString', Regexp.last_match(2), rendering_options)
end
# KaTeX should fix escaped `$` within fenced blocks, this addresses instances outside of math mode
rendered_str.to_s.gsub(/\\[$]/, '$').to_s
end
def fix_code(input)
updated = false
html = Nokogiri::HTML.fragment(input)
Jekyll.logger.debug LOG_TOPIC, "Fixing - #{input}"
html.css("code, code span").each do |c|
if c.css('*').empty? && c.content['$']
updated = true
Jekyll.logger.debug LOG_TOPIC, "current tag - #{c}"
content = c.content
content['$'] = '\$'
c.content = content
Jekyll.logger.debug LOG_TOPIC, "current tag now - #{c}/#{content}"
end
end
output = html.to_s
Jekyll.logger.debug LOG_TOPIC, "Fixed - #{output}"
if updated then html.to_s else input end
end
end
end
end
Liquid::Template.register_tag('katexmmx', Jekyll::Tags::KatexMathModeFixed)
What it basically does, is searching for <pre><code><span>AST element</span></code></pre>
(block case, code span
css selector) or <code>inline<code>
(inline code, code
selector) to using XPath and then replace each $
with \$
. From what I saw it worked, though it was a bit slower than normal katexmm
and I think a lot slower than kramdown build-in support for katex. But it might be some starting point.
@MateuszKubuszok Thank you for spending so much time to help document and understand the issue. Unfortunately I'm in the middle of a lot of life events and probably won't have time to address this issue until after April.
If you want to open a PR I can dedicate time to helping you get any fixes in. If you don't mind waiting, I can return to this in a few months.
When I have code block (rendered by rouge) in my post.md e.g.
and I want to render LaTeX as well using
$$
tags in markdown andkatexmm
in layout:I end up with KaTeX exception
Liquid Exception: ParseError: KaTeX parse error: Expected 'EOF', got … in /_layouts/post.html
. MathJax simply ignores unmatched$
so it wasn't a problem before migration. Additionally, since rouge runs somewhere between putting templates together and running KaTeX, so neither escaping$
manually in all .md files, nor writing a custom filter that prepends all$
with\
help. This error happens on $ pairing, sothrow_error: false
cannot fix it.It would be helpful to be able to ignore
$
at least in certain contexts, like e.g.code
tag.