Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize markdown parsing with Kramdown by reusing the options and parser objects #8013

Merged
merged 5 commits into from Feb 26, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 59 additions & 1 deletion lib/jekyll/converters/markdown/kramdown_parser.rb
@@ -1,5 +1,63 @@
# Frozen-string-literal: true

module Kramdown
# A Kramdown::Document subclass meant to optimize memory usage from initializing
# a kramdown document for parsing.
#
# The optimization is by using the same options Hash (and its derivatives) for
# converting all Markdown documents in a Jekyll site.
class JekyllDocument < Document
class << self
attr_reader :options, :parser

# The implementation is basically the core logic in +Kramdown::Document#initialize+
#
# rubocop:disable Naming/MemoizedInstanceVariableName
def setup(options)
@cache ||= {}

# reset variables on a subsequent set up with a different options Hash
unless @cache[:id] == options.hash
@options = @parser = nil
@cache[:id] = options.hash
end

@options ||= Options.merge(options).freeze
@parser ||= begin
parser_name = (@options[:input] || "kramdown").to_s
parser_name = parser_name[0..0].upcase + parser_name[1..-1]
try_require("parser", parser_name)

if Parser.const_defined?(parser_name)
Parser.const_get(parser_name)
else
raise Kramdown::Error, "kramdown has no parser to handle the specified " \
"input format: #{@options[:input]}"
end
end
end
# rubocop:enable Naming/MemoizedInstanceVariableName

private

def try_require(type, name)
require "kramdown/#{type}/#{Utils.snake_case(name)}"
rescue LoadError
false
end
end

def initialize(source, options = {})
JekyllDocument.setup(options)

@options = JekyllDocument.options
@root, @warnings = JekyllDocument.parser.parse(source, @options)
end
end
end

#

module Jekyll
module Converters
class Markdown
Expand Down Expand Up @@ -37,7 +95,7 @@ def setup
end

def convert(content)
document = Kramdown::Document.new(content, @config)
document = Kramdown::JekyllDocument.new(content, @config)
html_output = document.to_html
if @config["show_warnings"]
document.warnings.each do |warning|
Expand Down