diff --git a/Gemfile b/Gemfile index df6f5dc..74bfd75 100644 --- a/Gemfile +++ b/Gemfile @@ -5,3 +5,5 @@ source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem 'nokogiri' +gem 'execjs' +gem 'duktape' diff --git a/Gemfile.lock b/Gemfile.lock index aaa8279..096da3a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,8 @@ GEM remote: https://rubygems.org/ specs: + duktape (2.7.0.0) + execjs (2.9.1) mini_portile2 (2.8.6) nokogiri (1.15.6) mini_portile2 (~> 2.8.2) @@ -11,6 +13,8 @@ PLATFORMS ruby DEPENDENCIES + duktape + execjs nokogiri BUNDLED WITH diff --git a/convert.rb b/convert.rb new file mode 100644 index 0000000..1b6433c --- /dev/null +++ b/convert.rb @@ -0,0 +1,48 @@ +require "execjs" +require "nokogiri" +require "net/http" +require "json" +require "cgi" + +class KatexRenderer + def initialize(source) + @context = ExecJS.compile(source) + @inline_cache = {} + @display_cache = {} + end + + def render(display, string) + cache = display ? @display_cache : @inline_cache + comment = display ? "display" : string + string = CGI.unescapeHTML string + + cache.fetch(string) do + puts " Rendering #{comment}" + options = { "throwOnError" => false, "displayMode" => display } + cache[string] = @context.call("katex.renderToString", string, options) + end + end + + def substitute(content) + rendered = content.gsub /\\\(((?:[^\\]|\\[^\)])*)\\\)/ do |match| + render(false, $~[1]) + end + rendered = rendered.gsub /\$\$((?:[^\$]|$[^\$])*)\$\$/ do |match| + render(true, $~[1]) + end + return rendered + end +end + +ExecJS.runtime = ExecJS::Runtimes::Duktape + +renderer = KatexRenderer.new(Net::HTTP.get(URI("https://static.danilafe.com/katex/katex.min.js"))) +files = ARGV[0..-1] +files.each do |file| + puts "Rendering file: #{file}" + document = Nokogiri::HTML.parse(File.open(file)) + document.search('//*[not(ancestor-or-self::code or ancestor-or-self::script)]/text()').each do |t| + t.replace(renderer.substitute(t.content)) + end + File.write(file, document.to_html(encoding: 'UTF-8')) +end