I use KaTeX in VSCode extension Markdown All in One for notes and homework. It's by far the easiest and most flexible way.
Markdown is such a markup language (see the paradox? lol) without a widely-accepted, strong official organization regularizing its syntax and grammar. Typical standards includes:
Implementation of Javascript libraries into Markdown, such as KaTeX, is done independently by Markdown processors, thus creating even more variants of syntax and grammar.
In an attempt to use the same syntax and grammar throughout my Markdown documents, i.e KaTeX with VSCode, Jekyll, and WordPress Markdown, and considering the possible transplantation to LaTeX, I adopt the following configuration for most consistent experience.
VSCode
Markdown All in One, with default settings such that the following is adopted
inline equation $c$ and block equation is coded by
$$
E = mc^2
$$
rendered as:
inline equation c and block equation is coded by
other syntax like \(\)
and \[\]
are also supported.
Jekyll
Two methods, server-side and client-side, are experimented. Client-side method is preferred due to flexibility on custom delimiter syntax.
Server-side Method
Server-side gem
# KaTeX
gem 'katex', '~> 0.6.0'
gem "kramdown-math-katex"
config.yml
# Build settings
markdown: kramdown
kramdown:
math_engine: katex
math_engine_opts: {}
To support inline syntax $
, do the following change in ~/gems/gems/kramdown-2.3.0/lib/kramdown/parser/kramdown/math.rb
#INLINE_MATH_START = /\$\$(.*?)\$\$/m
INLINE_MATH_START = /\$(.*?[\S])\$/m
Off topic, the footnote regex need to modify as well, in ~/gems/gems/kramdown-2.3.0/lib/kramdown/parser/kramdown/footnote.rb
ALD_FN_NAME = /[^\[]*/
FOOTNOTE_DEFINITION_START = /^#{OPT_SPACE}\[\^(#{ALD_FN_NAME})\]:\s*?(.*?\n#{CODEBLOCK_MATCH})/
FOOTNOTE_MARKER_START = /\[\^(#{ALD_FN_NAME})\]/
Client-side Method
No gem required.
config.yml
# Build settings
markdown: kramdown
kramdown:
math_engine: null
such that default math_engine: mathjax
is not enabled.
HTML template header
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-zB1R0rpPzHqg7Kpt0Aljp8JPLqbXI3bhnPWROx27a9N0Ll6ZP/+DiW/UqRcLbRjq" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js" integrity="sha384-g7c+Jr9ZivxKLnZTDUhnkOnsh30B4H0rpLUpJ4jAIKs4fnJI+sEnkvrMWph2EDg4" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js" integrity="sha384-mll67QQFJfxn0IYznZYonOWZ644AWYC+Pt2cHqMaRhXVrursRwvLnLaebdGIlYNa" crossorigin="anonymous"></script>
HTML template footer
<script>
// Load KaTeX
document.addEventListener("DOMContentLoaded", function () {
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
{ left: "\(", right: "\)", display: false },
{ left: "\[", right: "\]", display: true },
],
});
});
</script>
thus defined all 4 delimiters. Note that this method is potentially dangerous since delimiters are used instead of regex.
WordPress
I use Githuber MD as my preferred github editor. I've tried WP-Editor.md but that one gots too many bugs even after years of development.
A quick and dirty hack to get my delimiters work:
replacing original inline style with display style,
wp-githuber-md/src/Modules/KaTeX.php
public static function katex_inline_markup( $content ) {
//replace original incline style with display style
//$regex = '%<code>\$\$((?:[^$]+ |(?<=(?<!\\\\)\\\\)\$ )+)(?<!\\\\)\$\$<\/code>%ix';
$regex = '%(\$\$)((?:[^$]+ |(?<=(?<!\\\\)\\\\)\$ )+)(?<!\\\\)(\$\$)%ix';
$content = preg_replace_callback( $regex, function() {
$matches = func_get_arg(0);
if ( ! empty( $matches[1] ) ) {
$katex = $matches[1];
$katex = str_replace( array( '<', '>', '"', ''', '&', '&', "\n", "\r" ), array( '<', '>', '"', "'", '&', '&', ' ', ' ' ), $katex );
//solve escape problem, temporarily
$katex = str_replace( '\\', '\\\\', $katex );
$katex = str_replace( '_', '\_', $katex );
//return '<code class="katex-inline">' . trim( $katex ) . '</code>';
return $katex;
}
}, $content );
return $content;
}
Reorder the rendering steps to have KaTeX rendered before Markdown.
wp-githuber-md/src/Controllers/Markdown.php
// If we're not using the code shortcode, prevent over-encoding.
if ( $args['decode_code_blocks'] ) {
$text = $this->restore_code_blocks( $text );
}
// Reordered Render KaTeX inline markup.
if ( $this->is_support_katex ) {
$text = ModuleKaTeX::katex_inline_markup( $text );
}
// Transform it!
$text = $this->get_parser()->transform( $text );
// Fetch remote images.
if ( $this->is_convert_remote_image() ) {
$text = $this->convert_remote_image( $text );
}
// Render Github Flavored Markdown task lists if this module is enabled.
if ( $this->is_support_task_list ) {
$text = ModuleTaskList::parse_gfm_task_list( $text );
}
// Render KaTeX inline markup.
// if ( $this->is_support_katex ) {
// $text = ModuleKaTeX::katex_inline_markup( $text );
//}
// Render MathJax inline markup.
if ( $this->is_support_mathjax ) {
$text = ModuleMathJax::mathjax_inline_markup( $text );
}
// Markdown inserts extra spaces to make itself work. Buh-bye.
$text = rtrim( $text );
then add same code to header and footer as Jekyll client method
HTML template header
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-zB1R0rpPzHqg7Kpt0Aljp8JPLqbXI3bhnPWROx27a9N0Ll6ZP/+DiW/UqRcLbRjq" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js" integrity="sha384-g7c+Jr9ZivxKLnZTDUhnkOnsh30B4H0rpLUpJ4jAIKs4fnJI+sEnkvrMWph2EDg4" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js" integrity="sha384-mll67QQFJfxn0IYznZYonOWZ644AWYC+Pt2cHqMaRhXVrursRwvLnLaebdGIlYNa" crossorigin="anonymous"></script>
HTML template footer
<script>
// Load KaTeX
document.addEventListener("DOMContentLoaded", function () {
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
{ left: "\(", right: "\)", display: false },
{ left: "\[", right: "\]", display: true },
],
});
});
</script>
and we are all set.