diff options
Diffstat (limited to 'vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown')
54 files changed, 8537 insertions, 0 deletions
diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter.rb new file mode 100644 index 0000000..0055a14 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter.rb @@ -0,0 +1,68 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/utils' + +module Kramdown + + # This module contains all available converters, i.e. classes that take a root Element and convert + # it to a specific output format. The result is normally a string. For example, the + # Converter::Html module converts an element tree into valid HTML. + # + # Converters use the Base class for common functionality (like applying a template to the output) + # \- see its API documentation for how to create a custom converter class. + module Converter + + autoload :Base, 'kramdown/converter/base' + autoload :Html, 'kramdown/converter/html' + autoload :Latex, 'kramdown/converter/latex' + autoload :Kramdown, 'kramdown/converter/kramdown' + autoload :Toc, 'kramdown/converter/toc' + autoload :RemoveHtmlTags, 'kramdown/converter/remove_html_tags' + autoload :HashAST, 'kramdown/converter/hash_ast' + autoload :HashAst, 'kramdown/converter/hash_ast' + autoload :Man, 'kramdown/converter/man' + + extend ::Kramdown::Utils::Configurable + + configurable(:syntax_highlighter) + + ['Minted', "Rouge"].each do |klass_name| + kn_down = klass_name.downcase.intern + add_syntax_highlighter(kn_down) do |converter, text, lang, type, opts| + require "kramdown/converter/syntax_highlighter/#{kn_down}" + klass = ::Kramdown::Utils.deep_const_get("::Kramdown::Converter::SyntaxHighlighter::#{klass_name}") + if !klass.const_defined?(:AVAILABLE) || klass::AVAILABLE + add_syntax_highlighter(kn_down, klass) + else + add_syntax_highlighter(kn_down) { nil } + end + syntax_highlighter(kn_down).call(converter, text, lang, type, opts) + end + end + + configurable(:math_engine) + + ["Mathjax"].each do |klass_name| + kn_down = klass_name.downcase.intern + add_math_engine(kn_down) do |converter, el, opts| + require "kramdown/converter/math_engine/#{kn_down}" + klass = ::Kramdown::Utils.deep_const_get("::Kramdown::Converter::MathEngine::#{klass_name}") + if !klass.const_defined?(:AVAILABLE) || klass::AVAILABLE + add_math_engine(kn_down, klass) + else + add_math_engine(kn_down) { nil } + end + math_engine(kn_down).call(converter, el, opts) + end + end + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/base.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/base.rb new file mode 100644 index 0000000..86cd2b4 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/base.rb @@ -0,0 +1,257 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'erb' +require 'kramdown/utils' +require 'kramdown/document' + +module Kramdown + + module Converter + + # == \Base class for converters + # + # This class serves as base class for all converters. It provides methods that can/should be + # used by all converters (like #generate_id) as well as common functionality that is + # automatically applied to the result (for example, embedding the output into a template). + # + # A converter object is used as a throw-away object, i.e. it is only used for storing the needed + # state information during conversion. Therefore one can't instantiate a converter object + # directly but only use the Base::convert method. + # + # == Implementing a converter + # + # Implementing a new converter is rather easy: just derive a new class from this class and put + # it in the Kramdown::Converter module (the latter is only needed if auto-detection should work + # properly). Then you need to implement the #convert method which has to contain the conversion + # code for converting an element and has to return the conversion result. + # + # The actual transformation of the document tree can be done in any way. However, writing one + # method per element type is a straight forward way to do it - this is how the Html and Latex + # converters do the transformation. + # + # Have a look at the Base::convert method for additional information! + class Base + + # Can be used by a converter for storing arbitrary information during the conversion process. + attr_reader :data + + # The hash with the conversion options. + attr_reader :options + + # The root element that is converted. + attr_reader :root + + # The warnings array. + attr_reader :warnings + + # Initialize the converter with the given +root+ element and +options+ hash. + def initialize(root, options) + @options = options + @root = root + @data = {} + @warnings = [] + end + private_class_method(:new, :allocate) + + # Returns whether the template should be applied before the conversion of the tree. + # + # Defaults to false. + def apply_template_before? + false + end + + # Returns whether the template should be applied after the conversion of the tree. + # + # Defaults to true. + def apply_template_after? + true + end + + # Convert the element tree +tree+ and return the resulting conversion object (normally a + # string) and an array with warning messages. The parameter +options+ specifies the conversion + # options that should be used. + # + # Initializes a new instance of the calling class and then calls the #convert method with + # +tree+ as parameter. + # + # If the +template+ option is specified and non-empty, the template is evaluate with ERB + # before and/or after the tree conversion depending on the result of #apply_template_before? + # and #apply_template_after?. If the template is evaluated before, an empty string is used for + # the body; if evaluated after, the result is used as body. See ::apply_template. + # + # The template resolution is done in the following way (for the converter ConverterName): + # + # 1. Look in the current working directory for the template. + # + # 2. Append +.converter_name+ (e.g. +.html+) to the template name and look for the resulting + # file in the current working directory (the form +.convertername+ is deprecated). + # + # 3. Append +.converter_name+ to the template name and look for it in the kramdown data + # directory (the form +.convertername+ is deprecated). + # + # 4. Check if the template name starts with 'string://' and if so, strip this prefix away and + # use the rest as template. + def self.convert(tree, options = {}) + converter = new(tree, ::Kramdown::Options.merge(options.merge(tree.options[:options] || {}))) + + if !converter.options[:template].empty? && converter.apply_template_before? + apply_template(converter, '') + end + result = converter.convert(tree) + if result.respond_to?(:encode!) && result.encoding != Encoding::BINARY + result.encode!(tree.options[:encoding] || + (raise ::Kramdown::Error, "Missing encoding option on root element")) + end + if !converter.options[:template].empty? && converter.apply_template_after? + result = apply_template(converter, result) + end + + [result, converter.warnings] + end + + # Convert the element +el+ and return the resulting object. + # + # This is the only method that has to be implemented by sub-classes! + def convert(_el) + raise NotImplementedError + end + + # Apply the +template+ using +body+ as the body string. + # + # The template is evaluated using ERB and the body is available in the @body instance variable + # and the converter object in the @converter instance variable. + def self.apply_template(converter, body) # :nodoc: + erb = ERB.new(get_template(converter.options[:template])) + obj = Object.new + obj.instance_variable_set(:@converter, converter) + obj.instance_variable_set(:@body, body) + erb.result(obj.instance_eval { binding }) + end + + # Return the template specified by +template+. + def self.get_template(template) # :nodoc: + format_ext = '.' + ::Kramdown::Utils.snake_case(name.split("::").last) + shipped = File.join(::Kramdown.data_dir, template + format_ext) + if File.exist?(template) + File.read(template) + elsif File.exist?(template + format_ext) + File.read(template + format_ext) + elsif File.exist?(shipped) + File.read(shipped) + elsif template.start_with?('string://') + template.delete_prefix("string://") + else + raise "The specified template file #{template} does not exist" + end + end + + # Add the given warning +text+ to the warning array. + def warning(text) + @warnings << text + end + + # Return +true+ if the header element +el+ should be used for the table of contents (as + # specified by the +toc_levels+ option). + def in_toc?(el) + @options[:toc_levels].include?(el.options[:level]) && (el.attr['class'] || '') !~ /\bno_toc\b/ + end + + # Return the output header level given a level. + # + # Uses the +header_offset+ option for adjusting the header level. + def output_header_level(level) + [[level + @options[:header_offset], 6].min, 1].max + end + + # Extract the code block/span language from the attributes. + def extract_code_language(attr) + if attr['class'] && attr['class'] =~ /\blanguage-\S+/ + attr['class'].scan(/\blanguage-(\S+)/).first.first + end + end + + # See #extract_code_language + # + # *Warning*: This version will modify the given attributes if a language is present. + def extract_code_language!(attr) + lang = extract_code_language(attr) + attr['class'] = attr['class'].sub(/\blanguage-\S+/, '').strip if lang + attr.delete('class') if lang && attr['class'].empty? + lang + end + + # Highlight the given +text+ in the language +lang+ with the syntax highlighter configured + # through the option 'syntax_highlighter'. + def highlight_code(text, lang, type, opts = {}) + return nil unless @options[:syntax_highlighter] + + highlighter = ::Kramdown::Converter.syntax_highlighter(@options[:syntax_highlighter]) + if highlighter + highlighter.call(self, text, lang, type, opts) + else + warning("The configured syntax highlighter #{@options[:syntax_highlighter]} is not available.") + nil + end + end + + # Format the given math element with the math engine configured through the option + # 'math_engine'. + def format_math(el, opts = {}) + return nil unless @options[:math_engine] + + engine = ::Kramdown::Converter.math_engine(@options[:math_engine]) + if engine + engine.call(self, el, opts) + else + warning("The configured math engine #{@options[:math_engine]} is not available.") + nil + end + end + + # Generate an unique alpha-numeric ID from the the string +str+ for use as a header ID. + # + # Uses the option +auto_id_prefix+: the value of this option is prepended to every generated + # ID. + def generate_id(str) + str = ::Kramdown::Utils::Unidecoder.decode(str) if @options[:transliterated_header_ids] + gen_id = basic_generate_id(str) + gen_id = 'section' if gen_id.empty? + @used_ids ||= {} + if @used_ids.key?(gen_id) + gen_id += "-#{@used_ids[gen_id] += 1}" + else + @used_ids[gen_id] = 0 + end + @options[:auto_id_prefix] + gen_id + end + + # The basic version of the ID generator, without any special provisions for empty or unique + # IDs. + def basic_generate_id(str) + gen_id = str.gsub(/^[^a-zA-Z]+/, '') + gen_id.tr!('^a-zA-Z0-9 -', '') + gen_id.tr!(' ', '-') + gen_id.downcase! + gen_id + end + + SMART_QUOTE_INDICES = {lsquo: 0, rsquo: 1, ldquo: 2, rdquo: 3} # :nodoc: + + # Return the entity that represents the given smart_quote element. + def smart_quote_entity(el) + res = @options[:smart_quotes][SMART_QUOTE_INDICES[el.value]] + ::Kramdown::Utils::Entities.entity(res) + end + + end + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/hash_ast.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/hash_ast.rb new file mode 100644 index 0000000..95714d4 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/hash_ast.rb @@ -0,0 +1,38 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser' +require 'kramdown/converter' +require 'kramdown/utils' + +module Kramdown + + module Converter + + # Converts a Kramdown::Document to a nested hash for further processing or debug output. + class HashAST < Base + + def convert(el) + hash = {type: el.type} + hash[:attr] = el.attr unless el.attr.empty? + hash[:value] = el.value unless el.value.nil? + hash[:options] = el.options unless el.options.empty? + unless el.children.empty? + hash[:children] = [] + el.children.each {|child| hash[:children] << convert(child) } + end + hash + end + + end + + HashAst = HashAST + + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/html.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/html.rb new file mode 100644 index 0000000..51ac9eb --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/html.rb @@ -0,0 +1,545 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser' +require 'kramdown/converter' +require 'kramdown/utils' + +module Kramdown + + module Converter + + # Converts a Kramdown::Document to HTML. + # + # You can customize the HTML converter by sub-classing it and overriding the +convert_NAME+ + # methods. Each such method takes the following parameters: + # + # [+el+] The element of type +NAME+ to be converted. + # + # [+indent+] A number representing the current amount of spaces for indent (only used for + # block-level elements). + # + # The return value of such a method has to be a string containing the element +el+ formatted as + # HTML element. + class Html < Base + + include ::Kramdown::Utils::Html + include ::Kramdown::Parser::Html::Constants + + # The amount of indentation used when nesting HTML tags. + attr_accessor :indent + + # Initialize the HTML converter with the given Kramdown document +doc+. + def initialize(root, options) + super + @footnote_counter = @footnote_start = @options[:footnote_nr] + @footnotes = [] + @footnotes_by_name = {} + @footnote_location = nil + @toc = [] + @toc_code = nil + @indent = 2 + @stack = [] + + # stash string representation of symbol to avoid allocations from multiple interpolations. + @highlighter_class = " highlighter-#{options[:syntax_highlighter]}" + @dispatcher = Hash.new {|h, k| h[k] = :"convert_#{k}" } + end + + # Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of + # the element. + def convert(el, indent = -@indent) + send(@dispatcher[el.type], el, indent) + end + + # Return the converted content of the children of +el+ as a string. The parameter +indent+ has + # to be the amount of indentation used for the element +el+. + # + # Pushes +el+ onto the @stack before converting the child elements and pops it from the stack + # afterwards. + def inner(el, indent) + result = +'' + indent += @indent + @stack.push(el) + el.children.each do |inner_el| + result << send(@dispatcher[inner_el.type], inner_el, indent) + end + @stack.pop + result + end + + def convert_blank(_el, _indent) + "\n" + end + + def convert_text(el, _indent) + escaped = escape_html(el.value, :text) + @options[:remove_line_breaks_for_cjk] ? fix_cjk_line_break(escaped) : escaped + end + + def convert_p(el, indent) + if el.options[:transparent] + inner(el, indent) + elsif el.children.size == 1 && el.children.first.type == :img && + el.children.first.options[:ial]&.[](:refs)&.include?('standalone') + convert_standalone_image(el, indent) + else + format_as_block_html("p", el.attr, inner(el, indent), indent) + end + end + + # Helper method used by +convert_p+ to convert a paragraph that only contains a single :img + # element. + def convert_standalone_image(el, indent) + figure_attr = el.attr.dup + image_attr = el.children.first.attr.dup + + if image_attr.key?('class') && !figure_attr.key?('class') + figure_attr['class'] = image_attr.delete('class') + end + if image_attr.key?('id') && !figure_attr.key?('id') + figure_attr['id'] = image_attr.delete('id') + end + + body = "#{' ' * (indent + @indent)}<img#{html_attributes(image_attr)} />\n" \ + "#{' ' * (indent + @indent)}<figcaption>#{image_attr['alt']}</figcaption>\n" + format_as_indented_block_html("figure", figure_attr, body, indent) + end + + def convert_codeblock(el, indent) + attr = el.attr.dup + lang = extract_code_language!(attr) + hl_opts = {} + highlighted_code = highlight_code(el.value, el.options[:lang] || lang, :block, hl_opts) + + if highlighted_code + add_syntax_highlighter_to_class_attr(attr, lang || hl_opts[:default_lang]) + "#{' ' * indent}<div#{html_attributes(attr)}>#{highlighted_code}#{' ' * indent}</div>\n" + else + result = escape_html(el.value) + result.chomp! + if el.attr['class'].to_s =~ /\bshow-whitespaces\b/ + result.gsub!(/(?:(^[ \t]+)|([ \t]+$)|([ \t]+))/) do |m| + suffix = ($1 ? '-l' : ($2 ? '-r' : '')) + m.scan(/./).map do |c| + case c + when "\t" then "<span class=\"ws-tab#{suffix}\">\t</span>" + when " " then "<span class=\"ws-space#{suffix}\">⋅</span>" + end + end.join + end + end + code_attr = {} + code_attr['class'] = "language-#{lang}" if lang + "#{' ' * indent}<pre#{html_attributes(attr)}>" \ + "<code#{html_attributes(code_attr)}>#{result}\n</code></pre>\n" + end + end + + def convert_blockquote(el, indent) + format_as_indented_block_html("blockquote", el.attr, inner(el, indent), indent) + end + + def convert_header(el, indent) + attr = el.attr.dup + if @options[:auto_ids] && !attr['id'] + attr['id'] = generate_id(el.options[:raw_text]) + end + + if @options[:header_links] && attr['id'].to_s.length > 0 + link = Element.new(:a, nil, nil) + link.attr['href'] = "##{attr['id']}" + el.children.unshift(link) + end + + @toc << [el.options[:level], attr['id'], el.children] if attr['id'] && in_toc?(el) + level = output_header_level(el.options[:level]) + format_as_block_html("h#{level}", attr, inner(el, indent), indent) + end + + def convert_hr(el, indent) + "#{' ' * indent}<hr#{html_attributes(el.attr)} />\n" + end + + ZERO_TO_ONETWENTYEIGHT = (0..128).to_a.freeze + private_constant :ZERO_TO_ONETWENTYEIGHT + + def convert_ul(el, indent) + if !@toc_code && el.options.dig(:ial, :refs)&.include?('toc') + @toc_code = [el.type, el.attr, ZERO_TO_ONETWENTYEIGHT.map { rand(36).to_s(36) }.join] + @toc_code.last + elsif !@footnote_location && el.options.dig(:ial, :refs)&.include?('footnotes') + @footnote_location = ZERO_TO_ONETWENTYEIGHT.map { rand(36).to_s(36) }.join + else + format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent) + end + end + alias convert_ol convert_ul + + def convert_dl(el, indent) + format_as_indented_block_html("dl", el.attr, inner(el, indent), indent) + end + + def convert_li(el, indent) + output = ' ' * indent << "<#{el.type}" << html_attributes(el.attr) << ">" + res = inner(el, indent) + if el.children.empty? || (el.children.first.type == :p && el.children.first.options[:transparent]) + output << res << (res.match?(/\n\Z/) ? ' ' * indent : '') + else + output << "\n" << res << ' ' * indent + end + output << "</#{el.type}>\n" + end + alias convert_dd convert_li + + def convert_dt(el, indent) + attr = el.attr.dup + @stack.last.options[:ial][:refs].each do |ref| + if ref =~ /\Aauto_ids(?:-([\w-]+))?/ + attr['id'] = "#{$1}#{basic_generate_id(el.options[:raw_text])}".lstrip + break + end + end if !attr['id'] && @stack.last.options[:ial] && @stack.last.options[:ial][:refs] + format_as_block_html("dt", attr, inner(el, indent), indent) + end + + def convert_html_element(el, indent) + res = inner(el, indent) + if el.options[:category] == :span + "<#{el.value}#{html_attributes(el.attr)}" + \ + (res.empty? && HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) ? " />" : ">#{res}</#{el.value}>") + else + output = +'' + if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw + output << ' ' * indent + end + output << "<#{el.value}#{html_attributes(el.attr)}" + if el.options[:is_closed] && el.options[:content_model] == :raw + output << " />" + elsif !res.empty? && el.options[:content_model] != :block + output << ">#{res}</#{el.value}>" + elsif !res.empty? + output << ">\n#{res.chomp}\n" << ' ' * indent << "</#{el.value}>" + elsif HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) + output << " />" + else + output << "></#{el.value}>" + end + output << "\n" if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw + output + end + end + + def convert_xml_comment(el, indent) + if el.options[:category] == :block && + (@stack.last.type != :html_element || @stack.last.options[:content_model] != :raw) + ' ' * indent << el.value << "\n" + else + el.value + end + end + alias convert_xml_pi convert_xml_comment + + def convert_table(el, indent) + format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent) + end + alias convert_thead convert_table + alias convert_tbody convert_table + alias convert_tfoot convert_table + alias convert_tr convert_table + + ENTITY_NBSP = ::Kramdown::Utils::Entities.entity('nbsp') # :nodoc: + + def convert_td(el, indent) + res = inner(el, indent) + type = (@stack[-2].type == :thead ? :th : :td) + attr = el.attr + alignment = @stack[-3].options[:alignment][@stack.last.children.index(el)] + if alignment != :default + attr = el.attr.dup + attr['style'] = (attr.key?('style') ? "#{attr['style']}; " : '') + "text-align: #{alignment}" + end + format_as_block_html(type, attr, res.empty? ? entity_to_str(ENTITY_NBSP) : res, indent) + end + + def convert_comment(el, indent) + if el.options[:category] == :block + "#{' ' * indent}<!-- #{el.value} -->\n" + else + "<!-- #{el.value} -->" + end + end + + def convert_br(_el, _indent) + "<br />" + end + + def convert_a(el, indent) + format_as_span_html("a", el.attr, inner(el, indent)) + end + + def convert_img(el, _indent) + "<img#{html_attributes(el.attr)} />" + end + + def convert_codespan(el, _indent) + attr = el.attr.dup + lang = extract_code_language(attr) + hl_opts = {} + result = highlight_code(el.value, lang, :span, hl_opts) + if result + add_syntax_highlighter_to_class_attr(attr, lang || hl_opts[:default_lang]) + else + result = escape_html(el.value) + end + + format_as_span_html('code', attr, result) + end + + def convert_footnote(el, _indent) + repeat = '' + name = @options[:footnote_prefix] + el.options[:name] + if (footnote = @footnotes_by_name[name]) + number = footnote[2] + repeat = ":#{footnote[3] += 1}" + else + number = @footnote_counter + @footnote_counter += 1 + @footnotes << [name, el.value, number, 0] + @footnotes_by_name[name] = @footnotes.last + end + formatted_link_text = sprintf(@options[:footnote_link_text], number) + "<sup id=\"fnref:#{name}#{repeat}\">" \ + "<a href=\"#fn:#{name}\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">" \ + "#{formatted_link_text}</a></sup>" + end + + def convert_raw(el, _indent) + if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('html') + el.value + (el.options[:category] == :block ? "\n" : '') + else + '' + end + end + + def convert_em(el, indent) + format_as_span_html(el.type, el.attr, inner(el, indent)) + end + alias convert_strong convert_em + + def convert_entity(el, _indent) + entity_to_str(el.value, el.options[:original]) + end + + TYPOGRAPHIC_SYMS = { + mdash: [::Kramdown::Utils::Entities.entity('mdash')], + ndash: [::Kramdown::Utils::Entities.entity('ndash')], + hellip: [::Kramdown::Utils::Entities.entity('hellip')], + laquo_space: [::Kramdown::Utils::Entities.entity('laquo'), + ::Kramdown::Utils::Entities.entity('nbsp')], + raquo_space: [::Kramdown::Utils::Entities.entity('nbsp'), + ::Kramdown::Utils::Entities.entity('raquo')], + laquo: [::Kramdown::Utils::Entities.entity('laquo')], + raquo: [::Kramdown::Utils::Entities.entity('raquo')], + } # :nodoc: + def convert_typographic_sym(el, _indent) + if (result = @options[:typographic_symbols][el.value]) + escape_html(result, :text) + else + TYPOGRAPHIC_SYMS[el.value].map {|e| entity_to_str(e) }.join + end + end + + def convert_smart_quote(el, _indent) + entity_to_str(smart_quote_entity(el)) + end + + def convert_math(el, indent) + if (result = format_math(el, indent: indent)) + result + else + attr = el.attr.dup + attr['class'] = "#{attr['class']} kdmath".lstrip + if el.options[:category] == :block + format_as_block_html('div', attr, "$$\n#{el.value}\n$$", indent) + else + format_as_span_html('span', attr, "$#{el.value}$") + end + end + end + + def convert_abbreviation(el, _indent) + title = @root.options[:abbrev_defs][el.value] + attr = @root.options[:abbrev_attr][el.value].dup + attr['title'] = title unless title.empty? + format_as_span_html("abbr", attr, el.value) + end + + def convert_root(el, indent) + result = inner(el, indent) + if @footnote_location + result.sub!(/#{@footnote_location}/, footnote_content.gsub(/\\/, "\\\\\\\\")) + else + result << footnote_content + end + if @toc_code + toc_tree = generate_toc_tree(@toc, @toc_code[0], @toc_code[1] || {}) + text = toc_tree.children.empty? ? '' : convert(toc_tree, 0) + result.sub!(/#{@toc_code.last}/, text.gsub(/\\/, "\\\\\\\\")) + end + result + end + + # Format the given element as span HTML. + def format_as_span_html(name, attr, body) + "<#{name}#{html_attributes(attr)}>#{body}</#{name}>" + end + + # Format the given element as block HTML. + def format_as_block_html(name, attr, body, indent) + "#{' ' * indent}<#{name}#{html_attributes(attr)}>#{body}</#{name}>\n" + end + + # Format the given element as block HTML with a newline after the start tag and indentation + # before the end tag. + def format_as_indented_block_html(name, attr, body, indent) + "#{' ' * indent}<#{name}#{html_attributes(attr)}>\n#{body}#{' ' * indent}</#{name}>\n" + end + + # Add the syntax highlighter name to the 'class' attribute of the given attribute hash. And + # overwrites or add a "language-LANG" part using the +lang+ parameter if +lang+ is not nil. + def add_syntax_highlighter_to_class_attr(attr, lang = nil) + (attr['class'] = (attr['class'] || '') + @highlighter_class).lstrip! + attr['class'].sub!(/\blanguage-\S+|(^)/) { "language-#{lang}#{$1 ? ' ' : ''}" } if lang + end + + # Generate and return an element tree for the table of contents. + def generate_toc_tree(toc, type, attr) + sections = Element.new(type, nil, attr.dup) + sections.attr['id'] ||= 'markdown-toc' + stack = [] + toc.each do |level, id, children| + li = Element.new(:li, nil, nil, level: level) + li.children << Element.new(:p, nil, nil, transparent: true) + a = Element.new(:a, nil) + a.attr['href'] = "##{id}" + a.attr['id'] = "#{sections.attr['id']}-#{id}" + a.children.concat(fix_for_toc_entry(Marshal.load(Marshal.dump(children)))) + li.children.last.children << a + li.children << Element.new(type) + + success = false + until success + if stack.empty? + sections.children << li + stack << li + success = true + elsif stack.last.options[:level] < li.options[:level] + stack.last.children.last.children << li + stack << li + success = true + else + item = stack.pop + item.children.pop if item.children.last.children.empty? + end + end + end + until stack.empty? + item = stack.pop + item.children.pop if item.children.last.children.empty? + end + sections + end + + # Fixes the elements for use in a TOC entry. + def fix_for_toc_entry(elements) + remove_footnotes(elements) + unwrap_links(elements) + elements + end + + # Remove all link elements by unwrapping them. + def unwrap_links(elements) + elements.map! do |c| + unwrap_links(c.children) + c.type == :a ? c.children : c + end.flatten! + end + + # Remove all footnotes from the given elements. + def remove_footnotes(elements) + elements.delete_if do |c| + remove_footnotes(c.children) + c.type == :footnote + end + end + + # Obfuscate the +text+ by using HTML entities. + def obfuscate(text) + result = +'' + text.each_byte do |b| + result << (b > 128 ? b.chr : sprintf("&#%03d;", b)) + end + result.force_encoding(text.encoding) + result + end + + FOOTNOTE_BACKLINK_FMT = "%s<a href=\"#fnref:%s\" class=\"reversefootnote\" role=\"doc-backlink\">%s</a>" + + # Return an HTML ordered list with the footnote content for the used footnotes. + def footnote_content + ol = Element.new(:ol) + ol.attr['start'] = @footnote_start if @footnote_start != 1 + i = 0 + backlink_text = escape_html(@options[:footnote_backlink], :text) + while i < @footnotes.length + name, data, _, repeat = *@footnotes[i] + li = Element.new(:li, nil, 'id' => "fn:#{name}") + li.children = Marshal.load(Marshal.dump(data.children)) + + para = nil + if li.children.last.type == :p || @options[:footnote_backlink_inline] + parent = li + while !parent.children.empty? && ![:p, :header].include?(parent.children.last.type) + parent = parent.children.last + end + para = parent.children.last + insert_space = true + end + + unless para + li.children << (para = Element.new(:p)) + insert_space = false + end + + unless @options[:footnote_backlink].empty? + nbsp = entity_to_str(ENTITY_NBSP) + value = sprintf(FOOTNOTE_BACKLINK_FMT, (insert_space ? nbsp : ''), name, backlink_text) + para.children << Element.new(:raw, value) + (1..repeat).each do |index| + value = sprintf(FOOTNOTE_BACKLINK_FMT, nbsp, "#{name}:#{index}", + "#{backlink_text}<sup>#{index + 1}</sup>") + para.children << Element.new(:raw, value) + end + end + + ol.children << Element.new(:raw, convert(li, 4)) + i += 1 + end + if ol.children.empty? + '' + else + format_as_indented_block_html('div', {class: "footnotes", role: "doc-endnotes"}, convert(ol, 2), 0) + end + end + + end + + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/kramdown.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/kramdown.rb new file mode 100644 index 0000000..3be4a8d --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/kramdown.rb @@ -0,0 +1,458 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/converter' +require 'kramdown/utils' + +module Kramdown + + module Converter + + # Converts an element tree to the kramdown format. + class Kramdown < Base + + # :stopdoc: + + include ::Kramdown::Utils::Html + + def initialize(root, options) + super + @linkrefs = [] + @footnotes = [] + @abbrevs = [] + @stack = [] + @list_indent = @options[:list_indent] + @list_spacing = ' ' * (@list_indent - 2) + end + + def convert(el, opts = {indent: 0}) + res = send("convert_#{el.type}", el, opts) + res = res.dup if res.frozen? + if ![:html_element, :li, :dt, :dd, :td].include?(el.type) && (ial = ial_for_element(el)) + res << ial + res << "\n\n" if el.block? + elsif [:ul, :dl, :ol, :codeblock].include?(el.type) && opts[:next] && + ([el.type, :codeblock].include?(opts[:next].type) || + (opts[:next].type == :blank && opts[:nnext] && + [el.type, :codeblock].include?(opts[:nnext].type))) + res << "^\n\n" + elsif el.block? && + ![:li, :dd, :dt, :td, :th, :tr, :thead, :tbody, :tfoot, :blank].include?(el.type) && + (el.type != :html_element || @stack.last.type != :html_element) && + (el.type != :p || !el.options[:transparent]) && + !([:ul, :dl, :ol].include?(el.type) && @stack.last.type == :li) + res << "\n" + end + res + end + + def inner(el, opts = {indent: 0}) + @stack.push(el) + result = +'' + el.children.each_with_index do |inner_el, index| + options = opts.dup + options[:index] = index + options[:prev] = (index == 0 ? nil : el.children[index - 1]) + options[:pprev] = (index <= 1 ? nil : el.children[index - 2]) + options[:next] = (index == el.children.length - 1 ? nil : el.children[index + 1]) + options[:nnext] = (index >= el.children.length - 2 ? nil : el.children[index + 2]) + result << convert(inner_el, options) + end + @stack.pop + result + end + + def convert_blank(_el, _opts) + "" + end + + ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]{"'|])|^ {0,3}(:)/ + + def convert_text(el, opts) + if opts[:raw_text] || (@stack.last.type == :html_element && @stack.last.options[:content_model] == :raw) + el.value + else + result = el.value.gsub(/\A\n/) do + opts[:prev] && opts[:prev].type == :br ? '' : "\n" + end + result.gsub!(/\s+/, ' ') unless el.options[:cdata] + result.gsub!(ESCAPED_CHAR_RE) do + $1 || !opts[:prev] || opts[:prev].type == :br ? "\\#{$1 || $2}" : $& + end + result + end + end + + def convert_p(el, opts) + w = @options[:line_width] - opts[:indent].to_s.to_i + first, second, *rest = inner(el, opts).strip.gsub(/(.{1,#{w}})( +|$\n?)/, "\\1\n").split(/\n/) + first&.gsub!(/^(?:(#|>)|(\d+)\.(\s)|([+-]\s))/) { $1 || $4 ? "\\#{$1 || $4}" : "#{$2}\\.#{$3}" } + second&.gsub!(/^([=-]+\s*?)$/, "\\\1") + res = [first, second, *rest].compact.join("\n") + "\n" + res.gsub!(/^ {0,3}:/, "\\:") + if el.children.length == 1 && el.children.first.type == :math + res = "\\#{res}" + elsif res.start_with?('\$$') && res.end_with?("\\$$\n") + res.sub!(/^\\\$\$/, '\$\$') + end + res + end + + def convert_codeblock(el, _opts) + el.value.split("\n").map {|l| l.empty? ? " " : " #{l}" }.join("\n") + "\n" + end + + def convert_blockquote(el, opts) + opts[:indent] += 2 + inner(el, opts).chomp.split("\n").map {|l| "> #{l}" }.join("\n") << "\n" + end + + def convert_header(el, opts) + opts[:in_header] = true + res = +'' + res << "#{'#' * output_header_level(el.options[:level])} #{inner(el, opts)}" + res[-1, 1] = "\\#" if res[-1] == '#' + res << " {##{el.attr['id']}}" if el.attr['id'] && !el.attr['id'].strip.empty? + res << "\n" + end + + def convert_hr(_el, _opts) + "* * *\n" + end + + def convert_ul(el, opts) + inner(el, opts).sub(/\n+\Z/, "\n") + end + alias convert_ol convert_ul + alias convert_dl convert_ul + + def convert_li(el, opts) + sym, width = if @stack.last.type == :ul + ['* ' + @list_spacing, el.children.first && el.children.first.type == :codeblock ? 4 : @list_indent] + else + ["#{opts[:index] + 1}.".ljust(4), 4] + end + if (ial = ial_for_element(el)) + sym << ial << " " + end + + opts[:indent] += width + text = inner(el, opts) + newlines = text.scan(/\n*\Z/).first + first, *last = text.split("\n") + last = last.map {|l| " " * width + l }.join("\n") + text = (first.nil? ? "\n" : first + (last.empty? ? "" : "\n") + last + newlines) + if el.children.first && el.children.first.type == :p && !el.children.first.options[:transparent] + res = +"#{sym}#{text}" + res << "^\n" if el.children.size == 1 && @stack.last.children.last == el && + (@stack.last.children.any? {|c| !c.children.first || c.children.first.type != :p } || @stack.last.children.size == 1) + res + elsif el.children.first && el.children.first.type == :codeblock + "#{sym}\n #{text}" + else + "#{sym}#{text}" + end + end + + def convert_dd(el, opts) + sym, width = ": " + @list_spacing, (el.children.first && el.children.first.type == :codeblock ? 4 : @list_indent) + if (ial = ial_for_element(el)) + sym << ial << " " + end + + opts[:indent] += width + text = inner(el, opts) + newlines = text.scan(/\n*\Z/).first + first, *last = text.split("\n") + last = last.map {|l| " " * width + l }.join("\n") + text = first.to_s + (last.empty? ? "" : "\n") + last + newlines + text.chomp! if text =~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dd + text << "\n" if text !~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dt + text << "\n" if el.children.empty? + if el.children.first && el.children.first.type == :p && !el.children.first.options[:transparent] + "\n#{sym}#{text}" + elsif el.children.first && el.children.first.type == :codeblock + "#{sym}\n #{text}" + else + "#{sym}#{text}" + end + end + + def convert_dt(el, opts) + result = +'' + if (ial = ial_for_element(el)) + result << ial << " " + end + result << inner(el, opts) << "\n" + end + + HTML_TAGS_WITH_BODY = %w[div script iframe textarea th td] + + HTML_ELEMENT_TYPES = [:entity, :text, :html_element].freeze + private_constant :HTML_ELEMENT_TYPES + + def convert_html_element(el, opts) + markdown_attr = el.options[:category] == :block && el.children.any? do |c| + c.type != :html_element && + (c.type != :p || !c.options[:transparent] || + c.children.any? {|t| !HTML_ELEMENT_TYPES.member?(t.type) }) && + c.block? + end + opts[:force_raw_text] = true if %w[script pre code].include?(el.value) + opts[:raw_text] = opts[:force_raw_text] || opts[:block_raw_text] || \ + (el.options[:category] != :span && !markdown_attr) + opts[:block_raw_text] = true if el.options[:category] == :block && opts[:raw_text] + res = inner(el, opts) + if el.options[:category] == :span + "<#{el.value}#{html_attributes(el.attr)}" + \ + (!res.empty? || HTML_TAGS_WITH_BODY.include?(el.value) ? ">#{res}</#{el.value}>" : " />") + else + output = +'' + attr = el.attr.dup + attr['markdown'] = '1' if markdown_attr + output << "<#{el.value}#{html_attributes(attr)}" + if !res.empty? && el.options[:content_model] != :block + output << ">#{res}</#{el.value}>" + elsif !res.empty? + output << ">\n#{res}" << "</#{el.value}>" + elsif HTML_TAGS_WITH_BODY.include?(el.value) + output << "></#{el.value}>" + else + output << " />" + end + output << "\n" if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw + output + end + end + + def convert_xml_comment(el, _opts) + if el.options[:category] == :block && + (@stack.last.type != :html_element || @stack.last.options[:content_model] != :raw) + el.value + "\n" + else + el.value.dup + end + end + alias convert_xml_pi convert_xml_comment + + def convert_table(el, opts) + opts[:alignment] = el.options[:alignment] + inner(el, opts) + end + + def convert_thead(el, opts) + rows = inner(el, opts) + if opts[:alignment].all?(:default) + "#{rows}|#{'-' * 10}\n" + else + "#{rows}| " + opts[:alignment].map do |a| + case a + when :left then ":-" + when :right then "-:" + when :center then ":-:" + when :default then "-" + end + end.join(' ') << "\n" + end + end + + def convert_tbody(el, opts) + res = +'' + res << inner(el, opts) + res << '|' << '-' * 10 << "\n" if opts[:next] && opts[:next].type == :tbody + res + end + + def convert_tfoot(el, opts) + "|#{'=' * 10}\n#{inner(el, opts)}" + end + + def convert_tr(el, opts) + "| #{el.children.map {|c| convert(c, opts) }.join(' | ')} |\n" + end + + def convert_td(el, opts) + inner(el, opts) + end + + def convert_comment(el, _opts) + if el.options[:category] == :block + "{::comment}\n#{el.value}\n{:/}\n" + else + "{::comment}#{el.value}{:/}" + end + end + + def convert_br(_el, opts) + opts[:in_header] ? "<br />" : " \n" + end + + def convert_a(el, opts) + if el.attr['href'].empty? + "[#{inner(el, opts)}]()" + elsif el.attr['href'] =~ /^(?:http|ftp)/ || el.attr['href'].count("()") > 0 + index = if (link_el = @linkrefs.find {|c| c.attr['href'] == el.attr['href'] }) + @linkrefs.index(link_el) + 1 + else + @linkrefs << el + @linkrefs.size + end + "[#{inner(el, opts)}][#{index}]" + else + title = parse_title(el.attr['title']) + "[#{inner(el, opts)}](#{el.attr['href']}#{title})" + end + end + + def convert_img(el, _opts) + alt_text = el.attr['alt'].to_s.gsub(ESCAPED_CHAR_RE) { $1 ? "\\#{$1}" : $2 } + src = el.attr['src'].to_s + if src.empty? + "![#{alt_text}]()" + else + title = parse_title(el.attr['title']) + link = if src.count("()") > 0 + "<#{src}>" + else + src + end + "" + end + end + + def convert_codespan(el, _opts) + delim = (el.value.scan(/`+/).max || '') + '`' + "#{delim}#{' ' if delim.size > 1}#{el.value}#{' ' if delim.size > 1}#{delim}" + end + + def convert_footnote(el, _opts) + @footnotes << [el.options[:name], el.value] + "[^#{el.options[:name]}]" + end + + def convert_raw(el, _opts) + attr = (el.options[:type] || []).join(' ') + attr = " type=\"#{attr}\"" unless attr.empty? + if @stack.last.type == :html_element + el.value + elsif el.options[:category] == :block + "{::nomarkdown#{attr}}\n#{el.value}\n{:/}\n" + else + "{::nomarkdown#{attr}}#{el.value}{:/}" + end + end + + def convert_em(el, opts) + "*#{inner(el, opts)}*" + + (opts[:next] && [:em, :strong].include?(opts[:next].type) && !ial_for_element(el) ? '{::}' : '') + end + + def convert_strong(el, opts) + "**#{inner(el, opts)}**" + + (opts[:next] && [:em, :strong].include?(opts[:next].type) && !ial_for_element(el) ? '{::}' : '') + end + + def convert_entity(el, _opts) + entity_to_str(el.value, el.options[:original]) + end + + TYPOGRAPHIC_SYMS = { + mdash: '---', ndash: '--', hellip: '...', + laquo_space: '<< ', raquo_space: ' >>', + laquo: '<<', raquo: '>>' + } + def convert_typographic_sym(el, _opts) + TYPOGRAPHIC_SYMS[el.value] + end + + def convert_smart_quote(el, _opts) + el.value.to_s.match?(/[rl]dquo/) ? "\"" : "'" + end + + def convert_math(el, _opts) + "$$#{el.value}$$" + (el.options[:category] == :block ? "\n" : '') + end + + def convert_abbreviation(el, _opts) + el.value + end + + def convert_root(el, opts) + res = inner(el, opts) + res << create_link_defs + res << create_footnote_defs + res << create_abbrev_defs + res + end + + def create_link_defs + res = +'' + res << "\n\n" unless @linkrefs.empty? + @linkrefs.each_with_index do |el, i| + title = parse_title(el.attr['title']) + res << "[#{i + 1}]: #{el.attr['href']}#{title}\n" + end + res + end + + def create_footnote_defs + res = +'' + @footnotes.each do |name, data| + res << "[^#{name}]:\n" + res << inner(data).chomp.split("\n").map {|l| " #{l}" }.join("\n") + "\n\n" + end + res + end + + def create_abbrev_defs + return '' unless @root.options[:abbrev_defs] + res = +'' + @root.options[:abbrev_defs].each do |name, text| + res << "*[#{name}]: #{text}\n" + res << ial_for_element(Element.new(:unused, nil, @root.options[:abbrev_attr][name])).to_s << "\n\n" + end + res + end + + # Return the IAL containing the attributes of the element +el+. + def ial_for_element(el) + res = el.attr.map do |k, v| + next if [:img, :a].include?(el.type) && ['href', 'src', 'alt', 'title'].include?(k) + next if el.type == :header && k == 'id' && !v.strip.empty? + if v.nil? + '' + elsif k == 'class' && !v.empty? && !v.index(/[.#]/) + " " + v.split(/\s+/).map {|w| ".#{w}" }.join(" ") + elsif k == 'id' && !v.strip.empty? + " ##{v}" + else + " #{k}=\"#{v}\"" + end + end.compact.join + res = "toc" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) && + el.options.dig(:ial, :refs)&.include?('toc') + res = "footnotes" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) && + el.options.dig(:ial, :refs)&.include?('footnotes') + if el.type == :dl && el.options[:ial] && el.options[:ial][:refs] + auto_ids = el.options[:ial][:refs].select {|ref| ref.start_with?('auto_ids') }.join(" ") + res = auto_ids << (res.strip.empty? ? '' : " #{res}") unless auto_ids.empty? + end + res.strip.empty? ? nil : "{:#{res}}" + end + + def parse_title(attr) + attr.to_s.empty? ? '' : ' "' + attr.gsub(/"/, '"') + '"' + end + + # :startdoc: + + end + + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/latex.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/latex.rb new file mode 100644 index 0000000..25f2bbb --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/latex.rb @@ -0,0 +1,626 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'set' +require 'kramdown/converter' + +module Kramdown + + module Converter + + # Converts an element tree to LaTeX. + # + # This converter uses ideas from other Markdown-to-LaTeX converters like Pandoc and Maruku. + # + # You can customize this converter by sub-classing it and overriding the +convert_NAME+ methods. + # Each such method takes the following parameters: + # + # [+el+] The element of type +NAME+ to be converted. + # + # [+opts+] A hash containing processing options that are passed down from parent elements. The + # key :parent is always set and contains the parent element as value. + # + # The return value of such a method has to be a string containing the element +el+ formatted + # correctly as LaTeX markup. + class Latex < Base + + # Initialize the LaTeX converter with the +root+ element and the conversion +options+. + def initialize(root, options) + super + @data[:packages] = Set.new + end + + # Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of + # the element. + def convert(el, opts = {}) + send("convert_#{el.type}", el, opts) + end + + # Return the converted content of the children of +el+ as a string. + def inner(el, opts) + result = +'' + options = opts.dup.merge(parent: el) + el.children.each_with_index do |inner_el, index| + options[:index] = index + options[:result] = result + result << send("convert_#{inner_el.type}", inner_el, options) + end + result + end + + def convert_root(el, opts) + inner(el, opts) + end + + def convert_blank(_el, opts) + opts[:result].match?(/\n\n\Z|\A\Z/) ? "" : "\n" + end + + def convert_text(el, _opts) + escape(el.value) + end + + def convert_p(el, opts) + if el.children.size == 1 && el.children.first.type == :img && + !(img = convert_img(el.children.first, opts)).empty? + convert_standalone_image(el, opts, img) + else + "#{latex_link_target(el)}#{inner(el, opts)}\n\n" + end + end + + # Helper method used by +convert_p+ to convert a paragraph that only contains a single :img + # element. + def convert_standalone_image(el, _opts, img) + attrs = attribute_list(el) + "\\begin{figure}#{attrs}\n\\begin{center}\n#{img}\n\\end{center}\n" \ + "\\caption{#{escape(el.children.first.attr['alt'])}}\n" \ + "#{latex_link_target(el, true)}\n\\end{figure}#{attrs}\n" + end + + def convert_codeblock(el, _opts) + show_whitespace = el.attr['class'].to_s =~ /\bshow-whitespaces\b/ + lang = extract_code_language(el.attr) + + if @options[:syntax_highlighter] == :minted && + (highlighted_code = highlight_code(el.value, lang, :block)) + @data[:packages] << 'minted' + "#{latex_link_target(el)}#{highlighted_code}\n" + elsif show_whitespace || lang + options = [] + options << (show_whitespace ? "showspaces=true,showtabs=true" : "showspaces=false,showtabs=false") + options << "language=#{lang}" if lang + options << "basicstyle=\\ttfamily\\footnotesize,columns=fixed,frame=tlbr" + id = el.attr['id'] + options << "label=#{id}" if id + attrs = attribute_list(el) + "#{latex_link_target(el)}\\begin{lstlisting}[#{options.join(',')}]\n" \ + "#{el.value}\n\\end{lstlisting}#{attrs}\n" + else + "#{latex_link_target(el)}\\begin{verbatim}#{el.value}\\end{verbatim}\n" + end + end + + def convert_blockquote(el, opts) + latex_environment(el.children.size > 1 ? 'quotation' : 'quote', el, inner(el, opts)) + end + + def convert_header(el, opts) + type = @options[:latex_headers][output_header_level(el.options[:level]) - 1] + if ((id = el.attr['id']) || + (@options[:auto_ids] && (id = generate_id(el.options[:raw_text])))) && in_toc?(el) + "\\#{type}{#{inner(el, opts)}}\\hypertarget{#{id}}{}\\label{#{id}}\n\n" + else + "\\#{type}*{#{inner(el, opts)}}\n\n" + end + end + + def convert_hr(el, _opts) + attrs = attribute_list(el) + "#{latex_link_target(el)}\\begin{center}#{attrs}\n\\rule{3in}{0.4pt}\n\\end{center}#{attrs}\n" + end + + def convert_ul(el, opts) + if !@data[:has_toc] && el.options.dig(:ial, :refs)&.include?('toc') + @data[:has_toc] = true + '\tableofcontents' + else + latex_environment(el.type == :ul ? 'itemize' : 'enumerate', el, inner(el, opts)) + end + end + alias convert_ol convert_ul + + def convert_dl(el, opts) + latex_environment('description', el, inner(el, opts)) + end + + def convert_li(el, opts) + "\\item{} #{latex_link_target(el, true)}#{inner(el, opts).sub(/\n+\Z/, '')}\n" + end + + def convert_dt(el, opts) + "\\item[#{inner(el, opts)}] " + end + + def convert_dd(el, opts) + "#{latex_link_target(el)}#{inner(el, opts)}\n\n" + end + + def convert_html_element(el, opts) + case el.value + when 'i', 'em' + "\\emph{#{inner(el, opts)}}" + when 'b', 'strong' + "\\textbf{#{inner(el, opts)}}" + else + warning("Can't convert HTML element") + '' + end + end + + def convert_xml_comment(el, _opts) + el.value.split("\n").map {|l| "% #{l}" }.join("\n") + "\n" + end + + def convert_xml_pi(_el, _opts) + warning("Can't convert XML PI") + '' + end + + TABLE_ALIGNMENT_CHAR = {default: 'l', left: 'l', center: 'c', right: 'r'} # :nodoc: + + def convert_table(el, opts) + @data[:packages] << 'longtable' + align = el.options[:alignment].map {|a| TABLE_ALIGNMENT_CHAR[a] }.join('|') + attrs = attribute_list(el) + "#{latex_link_target(el)}\\begin{longtable}{|#{align}|}#{attrs}\n" \ + "\\hline\n#{inner(el, opts)}\\hline\n\\end{longtable}#{attrs}\n\n" + end + + def convert_thead(el, opts) + "#{inner(el, opts)}\\hline\n" + end + + def convert_tbody(el, opts) + inner(el, opts) + end + + def convert_tfoot(el, opts) + "\\hline \\hline \n#{inner(el, opts)}" + end + + def convert_tr(el, opts) + el.children.map {|c| send("convert_#{c.type}", c, opts) }.join(' & ') << "\\\\\n" + end + + def convert_td(el, opts) + inner(el, opts) + end + + def convert_comment(el, _opts) + el.value.split("\n").map {|l| "% #{l}" }.join("\n") << "\n" + end + + def convert_br(_el, opts) + res = +"\\newline" + res << "\n" if (c = opts[:parent].children[opts[:index] + 1]) && + (c.type != :text || c.value !~ /^\s*\n/) + res + end + + def convert_a(el, opts) + url = el.attr['href'] + if url.start_with?('#') + "\\hyperlink{#{url[1..-1].gsub('%', '\\%')}}{#{inner(el, opts)}}" + else + "\\href{#{url.gsub('%', '\\%')}}{#{inner(el, opts)}}" + end + end + + def convert_img(el, _opts) + line = el.options[:location] + if el.attr['src'].match?(/^(https?|ftps?):\/\//) + warning("Cannot include non-local image#{line ? " (line #{line})" : ''}") + '' + elsif !el.attr['src'].empty? + @data[:packages] << 'graphicx' + "#{latex_link_target(el)}\\includegraphics{#{el.attr['src']}}" + else + warning("Cannot include image with empty path#{line ? " (line #{line})" : ''}") + '' + end + end + + def convert_codespan(el, _opts) + lang = extract_code_language(el.attr) + if @options[:syntax_highlighter] == :minted && + (highlighted_code = highlight_code(el.value, lang, :span)) + @data[:packages] << 'minted' + "#{latex_link_target(el)}#{highlighted_code}" + else + "\\texttt{#{latex_link_target(el)}#{escape(el.value)}}" + end + end + + def convert_footnote(el, opts) + @data[:packages] << 'fancyvrb' + "\\footnote{#{inner(el.value, opts).rstrip}}" + end + + def convert_raw(el, _opts) + if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('latex') + el.value + (el.options[:category] == :block ? "\n" : '') + else + '' + end + end + + def convert_em(el, opts) + "\\emph{#{latex_link_target(el)}#{inner(el, opts)}}" + end + + def convert_strong(el, opts) + "\\textbf{#{latex_link_target(el)}#{inner(el, opts)}}" + end + + # Inspired by Maruku: entity conversion table based on the one from htmltolatex + # (http://sourceforge.net/projects/htmltolatex/), with some small adjustments/additions + ENTITY_CONV_TABLE = { + 913 => ['$A$'], + 914 => ['$B$'], + 915 => ['$\Gamma$'], + 916 => ['$\Delta$'], + 917 => ['$E$'], + 918 => ['$Z$'], + 919 => ['$H$'], + 920 => ['$\Theta$'], + 921 => ['$I$'], + 922 => ['$K$'], + 923 => ['$\Lambda$'], + 924 => ['$M$'], + 925 => ['$N$'], + 926 => ['$\Xi$'], + 927 => ['$O$'], + 928 => ['$\Pi$'], + 929 => ['$P$'], + 931 => ['$\Sigma$'], + 932 => ['$T$'], + 933 => ['$Y$'], + 934 => ['$\Phi$'], + 935 => ['$X$'], + 936 => ['$\Psi$'], + 937 => ['$\Omega$'], + 945 => ['$\alpha$'], + 946 => ['$\beta$'], + 947 => ['$\gamma$'], + 948 => ['$\delta$'], + 949 => ['$\epsilon$'], + 950 => ['$\zeta$'], + 951 => ['$\eta$'], + 952 => ['$\theta$'], + 953 => ['$\iota$'], + 954 => ['$\kappa$'], + 955 => ['$\lambda$'], + 956 => ['$\mu$'], + 957 => ['$\nu$'], + 958 => ['$\xi$'], + 959 => ['$o$'], + 960 => ['$\pi$'], + 961 => ['$\rho$'], + 963 => ['$\sigma$'], + 964 => ['$\tau$'], + 965 => ['$\upsilon$'], + 966 => ['$\phi$'], + 967 => ['$\chi$'], + 968 => ['$\psi$'], + 969 => ['$\omega$'], + 962 => ['$\varsigma$'], + 977 => ['$\vartheta$'], + 982 => ['$\varpi$'], + 8230 => ['\ldots'], + 8242 => ['$\prime$'], + 8254 => ['-'], + 8260 => ['/'], + 8472 => ['$\wp$'], + 8465 => ['$\Im$'], + 8476 => ['$\Re$'], + 8501 => ['$\aleph$'], + 8226 => ['$\bullet$'], + 8482 => ['$^{\rm TM}$'], + 8592 => ['$\leftarrow$'], + 8594 => ['$\rightarrow$'], + 8593 => ['$\uparrow$'], + 8595 => ['$\downarrow$'], + 8596 => ['$\leftrightarrow$'], + 8629 => ['$\hookleftarrow$'], + 8657 => ['$\Uparrow$'], + 8659 => ['$\Downarrow$'], + 8656 => ['$\Leftarrow$'], + 8658 => ['$\Rightarrow$'], + 8660 => ['$\Leftrightarrow$'], + 8704 => ['$\forall$'], + 8706 => ['$\partial$'], + 8707 => ['$\exists$'], + 8709 => ['$\emptyset$'], + 8711 => ['$\nabla$'], + 8712 => ['$\in$'], + 8715 => ['$\ni$'], + 8713 => ['$\notin$'], + 8721 => ['$\sum$'], + 8719 => ['$\prod$'], + 8722 => ['$-$'], + 8727 => ['$\ast$'], + 8730 => ['$\surd$'], + 8733 => ['$\propto$'], + 8734 => ['$\infty$'], + 8736 => ['$\angle$'], + 8743 => ['$\wedge$'], + 8744 => ['$\vee$'], + 8745 => ['$\cap$'], + 8746 => ['$\cup$'], + 8747 => ['$\int$'], + 8756 => ['$\therefore$', 'amssymb'], + 8764 => ['$\sim$'], + 8776 => ['$\approx$'], + 8773 => ['$\cong$'], + 8800 => ['$\neq$'], + 8801 => ['$\equiv$'], + 8804 => ['$\leq$'], + 8805 => ['$\geq$'], + 8834 => ['$\subset$'], + 8835 => ['$\supset$'], + 8838 => ['$\subseteq$'], + 8839 => ['$\supseteq$'], + 8836 => ['$\nsubset$', 'amssymb'], + 8853 => ['$\oplus$'], + 8855 => ['$\otimes$'], + 8869 => ['$\perp$'], + 8901 => ['$\cdot$'], + 8968 => ['$\rceil$'], + 8969 => ['$\lceil$'], + 8970 => ['$\lfloor$'], + 8971 => ['$\rfloor$'], + 9001 => ['$\rangle$'], + 9002 => ['$\langle$'], + 9674 => ['$\lozenge$', 'amssymb'], + 9824 => ['$\spadesuit$'], + 9827 => ['$\clubsuit$'], + 9829 => ['$\heartsuit$'], + 9830 => ['$\diamondsuit$'], + 38 => ['\&'], + 34 => ['"'], + 39 => ['\''], + 169 => ['\copyright'], + 60 => ['\textless'], + 62 => ['\textgreater'], + 338 => ['\OE'], + 339 => ['\oe'], + 352 => ['\v{S}'], + 353 => ['\v{s}'], + 376 => ['\"Y'], + 710 => ['\textasciicircum'], + 732 => ['\textasciitilde'], + 8211 => ['--'], + 8212 => ['---'], + 8216 => ['`'], + 8217 => ['\''], + 8220 => ['``'], + 8221 => ['\'\''], + 8224 => ['\dag'], + 8225 => ['\ddag'], + 8240 => ['\permil', 'wasysym'], + 8364 => ['\euro', 'eurosym'], + 8249 => ['\guilsinglleft'], + 8250 => ['\guilsinglright'], + 8218 => ['\quotesinglbase', 'mathcomp'], + 8222 => ['\quotedblbase', 'mathcomp'], + 402 => ['\textflorin', 'mathcomp'], + 381 => ['\v{Z}'], + 382 => ['\v{z}'], + 160 => ['~'], + 161 => ['\textexclamdown'], + 163 => ['\pounds'], + 164 => ['\currency', 'wasysym'], + 165 => ['\textyen', 'textcomp'], + 166 => ['\brokenvert', 'wasysym'], + 167 => ['\S'], + 171 => ['\guillemotleft'], + 187 => ['\guillemotright'], + 174 => ['\textregistered'], + 170 => ['\textordfeminine'], + 172 => ['$\neg$'], + 173 => ['\-'], + 176 => ['$\degree$', 'mathabx'], + 177 => ['$\pm$'], + 180 => ['\''], + 181 => ['$\mu$'], + 182 => ['\P'], + 183 => ['$\cdot$'], + 186 => ['\textordmasculine'], + 162 => ['\cent', 'wasysym'], + 185 => ['$^1$'], + 178 => ['$^2$'], + 179 => ['$^3$'], + 189 => ['$\frac{1}{2}$'], + 188 => ['$\frac{1}{4}$'], + 190 => ['$\frac{3}{4}'], + 192 => ['\`A'], + 193 => ['\\\'A'], + 194 => ['\^A'], + 195 => ['\~A'], + 196 => ['\"A'], + 197 => ['\AA'], + 198 => ['\AE'], + 199 => ['\cC'], + 200 => ['\`E'], + 201 => ['\\\'E'], + 202 => ['\^E'], + 203 => ['\"E'], + 204 => ['\`I'], + 205 => ['\\\'I'], + 206 => ['\^I'], + 207 => ['\"I'], + 208 => ['$\eth$', 'amssymb'], + 209 => ['\~N'], + 210 => ['\`O'], + 211 => ['\\\'O'], + 212 => ['\^O'], + 213 => ['\~O'], + 214 => ['\"O'], + 215 => ['$\times$'], + 216 => ['\O'], + 217 => ['\`U'], + 218 => ['\\\'U'], + 219 => ['\^U'], + 220 => ['\"U'], + 221 => ['\\\'Y'], + 222 => ['\Thorn', 'wasysym'], + 223 => ['\ss'], + 224 => ['\`a'], + 225 => ['\\\'a'], + 226 => ['\^a'], + 227 => ['\~a'], + 228 => ['\"a'], + 229 => ['\aa'], + 230 => ['\ae'], + 231 => ['\cc'], + 232 => ['\`e'], + 233 => ['\\\'e'], + 234 => ['\^e'], + 235 => ['\"e'], + 236 => ['\`i'], + 237 => ['\\\'i'], + 238 => ['\^i'], + 239 => ['\"i'], + 240 => ['$\eth$'], + 241 => ['\~n'], + 242 => ['\`o'], + 243 => ['\\\'o'], + 244 => ['\^o'], + 245 => ['\~o'], + 246 => ['\"o'], + 247 => ['$\divide$'], + 248 => ['\o'], + 249 => ['\`u'], + 250 => ['\\\'u'], + 251 => ['\^u'], + 252 => ['\"u'], + 253 => ['\\\'y'], + 254 => ['\thorn', 'wasysym'], + 255 => ['\"y'], + 8201 => ['\thinspace'], + 8194 => ['\hskip .5em\relax'], + 8195 => ['\quad'], + } # :nodoc: + ENTITY_CONV_TABLE.each_value {|v| v[0] = "#{v[0]}{}" } + + def entity_to_latex(entity) + text, package = ENTITY_CONV_TABLE[entity.code_point] + if text + @data[:packages] << package if package + text + else + warning("Couldn't find entity with code #{entity.code_point} in substitution table!") + '' + end + end + + def convert_entity(el, _opts) + entity_to_latex(el.value) + end + + TYPOGRAPHIC_SYMS = { + mdash: '---', ndash: '--', hellip: '\ldots{}', + laquo_space: '\guillemotleft{}~', raquo_space: '~\guillemotright{}', + laquo: '\guillemotleft{}', raquo: '\guillemotright{}' + } # :nodoc: + def convert_typographic_sym(el, _opts) + if (result = @options[:typographic_symbols][el.value]) + escape(result) + else + TYPOGRAPHIC_SYMS[el.value] + end + end + + def convert_smart_quote(el, opts) + res = entity_to_latex(smart_quote_entity(el)).chomp('{}') + res << "{}" if ((nel = opts[:parent].children[opts[:index] + 1]) && nel.type == :smart_quote) || res =~ /\w$/ + res + end + + def convert_math(el, _opts) + @data[:packages] += %w[amssymb amsmath amsthm amsfonts] + if el.options[:category] == :block + if el.value.match?(/\A\s*\\begin\{/) + el.value + else + latex_environment('displaymath', el, el.value) + end + else + "$#{el.value}$" + end + end + + def convert_abbreviation(el, _opts) + @data[:packages] += %w[acronym] + "\\ac{#{normalize_abbreviation_key(el.value)}}" + end + + # Normalize the abbreviation key so that it only contains allowed ASCII character + def normalize_abbreviation_key(key) + key.gsub(/\W/) {|m| m.unpack1('H*') } + end + + # Wrap the +text+ inside a LaTeX environment of type +type+. The element +el+ is passed on to + # the method #attribute_list -- the resulting string is appended to both the \\begin and the + # \\end lines of the LaTeX environment for easier post-processing of LaTeX environments. + def latex_environment(type, el, text) + attrs = attribute_list(el) + "\\begin{#{type}}#{latex_link_target(el)}#{attrs}\n#{text.rstrip}\n\\end{#{type}}#{attrs}\n" + end + + # Return a string containing a valid \hypertarget command if the element has an ID defined, or + # +nil+ otherwise. If the parameter +add_label+ is +true+, a \label command will also be used + # additionally to the \hypertarget command. + def latex_link_target(el, add_label = false) + if (id = el.attr['id']) + "\\hypertarget{#{id}}{}#{add_label ? "\\label{#{id}}" : ''}" + else + nil + end + end + + # Return a LaTeX comment containing all attributes as 'key="value"' pairs. + def attribute_list(el) + attrs = el.attr.map {|k, v| v.nil? ? '' : " #{k}=\"#{v}\"" }.compact.sort.join + attrs = " % #{attrs}" unless attrs.empty? + attrs + end + + ESCAPE_MAP = { + "^" => "\\^{}", + "\\" => "\\textbackslash{}", + "~" => "\\ensuremath{\\sim}", + "|" => "\\textbar{}", + "<" => "\\textless{}", + ">" => "\\textgreater{}", + "[" => "{[}", + "]" => "{]}", + }.merge(Hash[*"{}$%&_#".each_char.map {|c| [c, "\\#{c}"] }.flatten]) # :nodoc: + ESCAPE_RE = Regexp.union(*ESCAPE_MAP.collect {|k, _v| k }) # :nodoc: + + # Escape the special LaTeX characters in the string +str+. + def escape(str) + str.gsub(ESCAPE_RE) {|m| ESCAPE_MAP[m] } + end + + end + + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/man.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/man.rb new file mode 100644 index 0000000..50da45a --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/man.rb @@ -0,0 +1,300 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/converter' + +module Kramdown + + module Converter + + # Converts a Kramdown::Document to a manpage in groff format. See man(7), groff_man(7) and + # man-pages(7) for information regarding the output. + class Man < Base + + def convert(el, opts = {indent: 0, result: +''}) # :nodoc: + send("convert_#{el.type}", el, opts) + end + + private + + def inner(el, opts, use = :all) + arr = el.children.reject {|e| e.type == :blank } + arr.each_with_index do |inner_el, index| + next if use == :rest && index == 0 + break if use == :first && index > 0 + options = opts.dup + options[:parent] = el + options[:index] = index + options[:prev] = (index == 0 ? nil : arr[index - 1]) + options[:next] = (index == arr.length - 1 ? nil : arr[index + 1]) + convert(inner_el, options) + end + end + + def convert_root(el, opts) + @title_done = false + opts[:result] = +".\\\" generated by kramdown\n" + inner(el, opts) + opts[:result] + end + + def convert_blank(*) + end + alias convert_hr convert_blank + alias convert_xml_pi convert_blank + + def convert_p(el, opts) + if (opts[:index] != 0 && opts[:prev].type != :header) || + (opts[:parent].type == :blockquote && opts[:index] == 0) + opts[:result] << macro("P") + end + inner(el, opts) + newline(opts[:result]) + end + + def convert_header(el, opts) + return unless opts[:parent].type == :root + case el.options[:level] + when 1 + unless @title_done + @title_done = true + data = el.options[:raw_text].scan(/([^(]+)\s*\((\d\w*)\)(?:\s*-+\s*(.*))?/).first || + el.options[:raw_text].scan(/([^\s]+)\s*(?:-*\s+)?()(.*)/).first + return unless data && data[0] + name = data[0] + section = (data[1].to_s.empty? ? el.attr['data-section'] || '7' : data[1]) + description = (data[2].to_s.empty? ? nil : " - #{data[2]}") + date = el.attr['data-date'] ? quote(el.attr['data-date']) : nil + extra = (el.attr['data-extra'] ? quote(escape(el.attr['data-extra'].to_s)) : nil) + opts[:result] << macro("TH", quote(escape(name.upcase)), quote(section), date, extra) + if description + opts[:result] << macro("SH", "NAME") << escape("#{name}#{description}") << "\n" + end + end + when 2 + opts[:result] << macro("SH", quote(escape(el.options[:raw_text]))) + when 3 + opts[:result] << macro("SS", quote(escape(el.options[:raw_text]))) + else + warning("Header levels greater than three are not supported") + end + end + + def convert_codeblock(el, opts) + opts[:result] << macro("sp") << macro("RS", 4) << macro("EX") + opts[:result] << newline(escape(el.value, true)) + opts[:result] << macro("EE") << macro("RE") + end + + def convert_blockquote(el, opts) + opts[:result] << macro("RS") + inner(el, opts) + opts[:result] << macro("RE") + end + + def convert_ul(el, opts) + compact = (el.attr['class'] =~ /\bcompact\b/) + opts[:result] << macro("sp") << macro("PD", 0) if compact + inner(el, opts) + opts[:result] << macro("PD") if compact + end + alias convert_dl convert_ul + alias convert_ol convert_ul + + def convert_li(el, opts) + sym = (opts[:parent].type == :ul ? '\(bu' : "#{opts[:index] + 1}.") + opts[:result] << macro("IP", sym, 4) + inner(el, opts, :first) + if el.children.size > 1 + opts[:result] << macro("RS") + inner(el, opts, :rest) + opts[:result] << macro("RE") + end + end + + def convert_dt(el, opts) + opts[:result] << macro(opts[:prev] && opts[:prev].type == :dt ? "TQ" : "TP") + inner(el, opts) + opts[:result] << "\n" + end + + def convert_dd(el, opts) + inner(el, opts, :first) + if el.children.size > 1 + opts[:result] << macro("RS") + inner(el, opts, :rest) + opts[:result] << macro("RE") + end + opts[:result] << macro("sp") if opts[:next] && opts[:next].type == :dd + end + + TABLE_CELL_ALIGNMENT = {left: 'l', center: 'c', right: 'r', default: 'l'} + + def convert_table(el, opts) + opts[:alignment] = el.options[:alignment].map {|a| TABLE_CELL_ALIGNMENT[a] } + table_options = ["box"] + table_options << "center" if el.attr['class']&.match?(/\bcenter\b/) + opts[:result] << macro("TS") << "#{table_options.join(' ')} ;\n" + inner(el, opts) + opts[:result] << macro("TE") << macro("sp") + end + + def convert_thead(el, opts) + opts[:result] << opts[:alignment].map {|a| "#{a}b" }.join(' ') << " .\n" + inner(el, opts) + opts[:result] << "=\n" + end + + def convert_tbody(el, opts) + opts[:result] << ".T&\n" if opts[:index] != 0 + opts[:result] << opts[:alignment].join(' ') << " .\n" + inner(el, opts) + opts[:result] << (opts[:next].type == :tfoot ? "=\n" : "_\n") if opts[:next] + end + + def convert_tfoot(el, opts) + inner(el, opts) + end + + def convert_tr(el, opts) + inner(el, opts) + opts[:result] << "\n" + end + + def convert_td(el, opts) + result = opts[:result] + opts[:result] = +'' + inner(el, opts) + if opts[:result].include?("\n") + warning("Table cells using links are not supported") + result << "\t" + else + result << opts[:result] << "\t" + end + end + + def convert_html_element(*) + warning("HTML elements are not supported") + end + + def convert_xml_comment(el, opts) + newline(opts[:result]) << ".\"#{escape(el.value, true).rstrip.gsub(/\n/, "\n.\"")}\n" + end + alias convert_comment convert_xml_comment + + def convert_a(el, opts) + if el.children.size == 1 && el.children[0].type == :text && + el.attr['href'] == el.children[0].value + newline(opts[:result]) << macro("UR", escape(el.attr['href'])) << macro("UE") + elsif el.attr['href'].start_with?('mailto:') + newline(opts[:result]) << macro("MT", escape(el.attr['href'].sub(/^mailto:/, ''))) << + macro("UE") + else + newline(opts[:result]) << macro("UR", escape(el.attr['href'])) + inner(el, opts) + newline(opts[:result]) << macro("UE") + end + end + + def convert_img(_el, _opts) + warning("Images are not supported") + end + + def convert_em(el, opts) + opts[:result] << '\fI' + inner(el, opts) + opts[:result] << '\fP' + end + + def convert_strong(el, opts) + opts[:result] << '\fB' + inner(el, opts) + opts[:result] << '\fP' + end + + def convert_codespan(el, opts) + opts[:result] << "\\fB#{escape(el.value)}\\fP" + end + + def convert_br(_el, opts) + newline(opts[:result]) << macro("br") + end + + def convert_abbreviation(el, opts) + opts[:result] << escape(el.value) + end + + def convert_math(el, opts) + if el.options[:category] == :block + convert_codeblock(el, opts) + else + convert_codespan(el, opts) + end + end + + def convert_footnote(*) + warning("Footnotes are not supported") + end + + def convert_raw(*) + warning("Raw content is not supported") + end + + def convert_text(el, opts) + text = escape(el.value) + text.lstrip! if opts[:result][-1] == "\n" + opts[:result] << text + end + + def convert_entity(el, opts) + opts[:result] << unicode_char(el.value.code_point) + end + + def convert_smart_quote(el, opts) + opts[:result] << unicode_char(::Kramdown::Utils::Entities.entity(el.value.to_s).code_point) + end + + TYPOGRAPHIC_SYMS_MAP = { + mdash: '\(em', ndash: '\(em', hellip: '\.\.\.', + laquo_space: '\[Fo]', raquo_space: '\[Fc]', laquo: '\[Fo]', raquo: '\[Fc]' + } + + def convert_typographic_sym(el, opts) + opts[:result] << TYPOGRAPHIC_SYMS_MAP[el.value] + end + + def macro(name, *args) + ".#{[name, *args].compact.join(' ')}\n" + end + + def newline(text) + text << "\n" unless text[-1] == "\n" + text + end + + def quote(text) + "\"#{text.gsub(/"/, '\\"')}\"" + end + + def escape(text, preserve_whitespace = false) + text = (preserve_whitespace ? text.dup : text.gsub(/\s+/, ' ')) + text.gsub!('\\', "\\e") + text.gsub!(/^\./, '\\\\&.') + text.gsub!(/[.'-]/) {|m| "\\#{m}" } + text + end + + def unicode_char(codepoint) + "\\[u#{codepoint.to_s(16).rjust(4, '0')}]" + end + + end + + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/math_engine/mathjax.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/math_engine/mathjax.rb new file mode 100644 index 0000000..84e2144 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/math_engine/mathjax.rb @@ -0,0 +1,32 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown::Converter::MathEngine + + # Uses the MathJax javascript library for displaying math. + # + # Note that the javascript library itself is not include or linked, this has to be done + # separately. Only the math content is marked up correctly. + module Mathjax + + def self.call(converter, el, opts) + value = converter.escape_html(el.value) + result = el.options[:category] == :block ? "\\[#{value}\\]\n" : "\\(#{value}\\)" + if el.attr.empty? + result + elsif el.options[:category] == :block + converter.format_as_block_html('div', el.attr, result, opts[:indent]) + else + converter.format_as_span_html('span', el.attr, "$#{el.value}$") + end + end + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/remove_html_tags.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/remove_html_tags.rb new file mode 100644 index 0000000..af81ad5 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/remove_html_tags.rb @@ -0,0 +1,58 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/converter' + +module Kramdown + + module Converter + + # Removes all block (and optionally span) level HTML tags from the element tree. + # + # This converter can be used on parsed HTML documents to get an element tree that will only + # contain native kramdown elements. + # + # *Note* that the returned element tree may not be fully conformant (i.e. the content models of + # *some elements may be violated)! + # + # This converter modifies the given tree in-place and returns it. + class RemoveHtmlTags < Base + + def initialize(root, options) + super + @options[:template] = '' + end + + def convert(el) + real_el, el = el, el.value if el.type == :footnote + + children = el.children.dup + index = 0 + while index < children.length + if children[index].type == :xml_pi || + (children[index].type == :html_element && (children[index].value == 'style' || + children[index].value == 'script')) + children[index..index] = [] + elsif children[index].type == :html_element && + ((@options[:remove_block_html_tags] && children[index].options[:category] == :block) || + (@options[:remove_span_html_tags] && children[index].options[:category] == :span)) + children[index..index] = children[index].children + else + convert(children[index]) + index += 1 + end + end + el.children = children + real_el || el + end + + end + + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter.rb new file mode 100644 index 0000000..683acbf --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter.rb @@ -0,0 +1,56 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Converter + + # == Container for Syntax Highlighters + # + # This module serves as container for the syntax highlighters that can be used together with + # kramdown. + # + # A syntax highlighter should not store any data itself but should use the provided converter + # object to do so (See Kramdown::Converter::Base#data). + # + # == Implementing a Syntax Highlighter + # + # Implementing a new syntax highlighter is easy because it is just an object that needs to + # respond to #call. + # + # The method #call needs to take the following arguments: + # + # converter:: This argument contains the converter object that calls the syntax highlighter. It + # can be used, for example, to store data in Kramdown::Converter::Base#data for one + # conversion run. + # + # text:: The raw text that should be highlighted. + # + # lang:: The language that the text should be highlighted for (e.g. ruby, python, ...). + # + # type:: The type of text, either :span for span-level code or :block for a codeblock. + # + # opts:: A Hash with options that may be passed from the converter. + # + # The return value of the method should be the highlighted text, suitable for the given + # converter (e.g. HTML for the HTML converter). + # + # == Special Implementation Details + # + # HTML converter:: If the syntax highlighter is used with an HTML converter, it should return + # :block type text correctly wrapped (i.e. normally inside a pre-tag, but may + # also be a table-tag or just a div-tag) but :span type text *without* a + # code-tag! + # + # Also, a syntax highlighter should store the default highlighting language for + # the invocation in the +opts+ hash under the key :default_lang. + module SyntaxHighlighter + end + + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/minted.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/minted.rb new file mode 100644 index 0000000..2119f00 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/minted.rb @@ -0,0 +1,35 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown::Converter::SyntaxHighlighter + + # Uses Minted to highlight code blocks and code spans. + module Minted + + def self.call(converter, text, lang, type, _opts) + opts = converter.options[:syntax_highlighter_opts] + + # Fallback to default language + lang ||= opts[:default_lang] + + options = [] + options << "breaklines" if opts[:wrap] + options << "linenos" if opts[:line_numbers] + options << "frame=#{opts[:frame]}" if opts[:frame] + + if lang && type == :block + "\\begin{minted}[#{options.join(',')}]{#{lang}}\n#{text}\n\\end{minted}" + elsif lang && type == :span + "\\mintinline{#{lang}}{#{text}}" + else + nil + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/rouge.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/rouge.rb new file mode 100644 index 0000000..ed6a4f8 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/rouge.rb @@ -0,0 +1,85 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown::Converter::SyntaxHighlighter + + # Uses Rouge which is CSS-compatible to Pygments to highlight code blocks and code spans. + module Rouge + + begin + require 'rouge' + + # Highlighting via Rouge is available if this constant is +true+. + AVAILABLE = true + rescue LoadError, SyntaxError + AVAILABLE = false # :nodoc: + end + + def self.call(converter, text, lang, type, call_opts) + opts = options(converter, type) + call_opts[:default_lang] = opts[:default_lang] + return nil unless lang || opts[:default_lang] || opts[:guess_lang] + + lexer = ::Rouge::Lexer.find_fancy(lang || opts[:default_lang], text) + return nil if opts[:disable] || !lexer || (lexer.tag == "plaintext" && !opts[:guess_lang]) + + opts[:css_class] ||= 'highlight' # For backward compatibility when using Rouge 2.0 + formatter = formatter_class(opts).new(opts) + formatter.format(lexer.lex(text)) + end + + def self.options(converter, type) + prepare_options(converter) + converter.data[:syntax_highlighter_rouge][type] + end + + def self.prepare_options(converter) + return if converter.data.key?(:syntax_highlighter_rouge) + + cache = converter.data[:syntax_highlighter_rouge] = {} + + opts = converter.options[:syntax_highlighter_opts].dup + + span_opts = opts.delete(:span)&.dup || {} + block_opts = opts.delete(:block)&.dup || {} + normalize_keys(span_opts) + normalize_keys(block_opts) + + cache[:span] = opts.merge(span_opts) + cache[:span][:wrap] = false + + cache[:block] = opts.merge(block_opts) + end + + def self.normalize_keys(hash) + return if hash.empty? + + hash.keys.each do |k| + hash[k.kind_of?(String) ? Kramdown::Options.str_to_sym(k) : k] = hash.delete(k) + end + end + + def self.formatter_class(opts = {}) + case formatter = opts[:formatter] + when Class + formatter + when /\A[[:upper:]][[:alnum:]_]*\z/ + ::Rouge::Formatters.const_get(formatter, false) + else + # Available in Rouge 2.0 or later + ::Rouge::Formatters::HTMLLegacy + end + rescue NameError + # Fallback to Rouge 1.x + ::Rouge::Formatters::HTML + end + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/toc.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/toc.rb new file mode 100644 index 0000000..7ffbc5d --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/converter/toc.rb @@ -0,0 +1,69 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/converter' + +module Kramdown + + module Converter + + # Converts a Kramdown::Document to an element tree that represents the table of contents. + # + # The returned tree consists of Element objects of type :toc where the root element is just used + # as container object. Each :toc element contains as value the wrapped :header element and under + # the attribute key :id the header ID that should be used (note that this ID may not exist in + # the wrapped element). + # + # Since the TOC tree consists of special :toc elements, one cannot directly feed this tree to + # other converters! + class Toc < Base + + def initialize(root, options) + super + @toc = Element.new(:toc) + @stack = [] + @options[:template] = '' + end + + def convert(el) + if el.type == :header && in_toc?(el) + attr = el.attr.dup + attr['id'] = generate_id(el.options[:raw_text]) if @options[:auto_ids] && !attr['id'] + add_to_toc(el, attr['id']) if attr['id'] + else + el.children.each {|child| convert(child) } + end + @toc + end + + private + + def add_to_toc(el, id) + toc_element = Element.new(:toc, el, id: id) + + success = false + until success + if @stack.empty? + @toc.children << toc_element + @stack << toc_element + success = true + elsif @stack.last.value.options[:level] < el.options[:level] + @stack.last.children << toc_element + @stack << toc_element + success = true + else + @stack.pop + end + end + end + + end + + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/document.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/document.rb new file mode 100644 index 0000000..7a10e76 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/document.rb @@ -0,0 +1,139 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# +# = kramdown +# +# kramdown is fast, pure Ruby Markdown superset converter, using a strict syntax definition and +# supporting several common extensions. +# +# The kramdown library is mainly written to support the kramdown-to-HTML conversion chain. However, +# due to its flexibility it supports other input and output formats as well. Here is a list of the +# supported formats: +# +# * input formats: kramdown (a Markdown superset), Markdown, GFM, HTML +# * output formats: HTML, kramdown, LaTeX (and therefore PDF), PDF via Prawn +# +# All the documentation on the available input and output formats is available at +# http://kramdown.gettalong.org. +# +# == Usage +# +# kramdown has a simple API, so using kramdown is as easy as +# +# require 'kramdown' +# +# Kramdown::Document.new(text).to_html +# +# For detailed information have a look at the *\Kramdown::Document* class. +# +# == License +# +# MIT - see the COPYING file. + +require 'kramdown/version' +require 'kramdown/element' +require 'kramdown/error' +require 'kramdown/parser' +require 'kramdown/converter' +require 'kramdown/options' +require 'kramdown/utils' + +module Kramdown + + # Return the data directory for kramdown. + def self.data_dir + unless defined?(@data_dir) + require 'rbconfig' + @data_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'kramdown')) + @data_dir = File.expand_path(File.join(RbConfig::CONFIG["datadir"], "kramdown")) unless File.exist?(@data_dir) + raise "kramdown data directory not found! This is a bug, please report it!" unless File.directory?(@data_dir) + end + @data_dir + end + + # The main interface to kramdown. + # + # This class provides a one-stop-shop for using kramdown to convert text into various output + # formats. Use it like this: + # + # require 'kramdown' + # doc = Kramdown::Document.new('This *is* some kramdown text') + # puts doc.to_html + # + # The #to_html method is a shortcut for using the Converter::Html class. See #method_missing for + # more information. + # + # The second argument to the ::new method is an options hash for customizing the behaviour of the + # used parser and the converter. See ::new for more information! + class Document + + # The root Element of the element tree. It is immediately available after the ::new method has + # been called. + attr_accessor :root + + # The options hash which holds the options for parsing/converting the Kramdown document. + attr_reader :options + + # An array of warning messages. It is filled with warnings during the parsing phase (i.e. in + # ::new) and the conversion phase. + attr_reader :warnings + + # Create a new Kramdown document from the string +source+ and use the provided +options+. The + # options that can be used are defined in the Options module. + # + # The special options key :input can be used to select the parser that should parse the + # +source+. It has to be the name of a class in the Kramdown::Parser module. For example, to + # select the kramdown parser, one would set the :input key to +Kramdown+. If this key is not + # set, it defaults to +Kramdown+. + # + # The +source+ is immediately parsed by the selected parser so that the root element is + # immediately available and the output can be generated. + def initialize(source, options = {}) + @options = Options.merge(options).freeze + parser = (@options[:input] || 'kramdown').to_s + parser = parser[0..0].upcase + parser[1..-1] + try_require('parser', parser) + if Parser.const_defined?(parser) + @root, @warnings = Parser.const_get(parser).parse(source, @options) + else + raise Kramdown::Error, "kramdown has no parser to handle the specified " \ + "input format: #{@options[:input]}" + end + end + + # Check if a method is invoked that begins with +to_+ and if so, try to instantiate a converter + # class (i.e. a class in the Kramdown::Converter module) and use it for converting the document. + # + # For example, +to_html+ would instantiate the Kramdown::Converter::Html class. + def method_missing(id, *attr, &block) + if id.to_s =~ /^to_(\w+)$/ && (name = Utils.camelize($1)) && + try_require('converter', name) && Converter.const_defined?(name) + output, warnings = Converter.const_get(name).convert(@root, @options) + @warnings.concat(warnings) + output + else + super + end + end + + def inspect # :nodoc: + "<KD:Document: options=#{@options.inspect} root=#{@root.inspect} warnings=#{@warnings.inspect}>" + end + + # Try requiring a parser or converter class and don't raise an error if the file is not found. + def try_require(type, name) + require("kramdown/#{type}/#{Utils.snake_case(name)}") + true + rescue LoadError + true + end + protected :try_require + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/element.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/element.rb new file mode 100644 index 0000000..031c7dd --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/element.rb @@ -0,0 +1,551 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # Represents all elements in the element tree. + # + # kramdown only uses this one class for representing all available elements in an element tree + # (paragraphs, headers, emphasis, ...). The type of element can be set via the #type accessor. + # + # The root of a kramdown element tree has to be an element of type :root. It needs to have certain + # option keys set so that conversions work correctly. If only a part of a tree should be + # converted, duplicate the root node and assign the #children appropriately, e.g: + # + # root = doc.root + # new_root = root.dup + # new_root.children = [root.children[0]] # assign new array with elements to convert + # + # Following is a description of all supported element types. + # + # Note that the option :location may contain the start line number of an element in the source + # document. + # + # == Structural Elements + # + # === :root + # + # [Category] None + # [Usage context] As the root element of a document + # [Content model] Block-level elements + # + # Represents the root of a kramdown document. + # + # The root element contains the following option keys: + # + # :encoding:: When running on Ruby 1.9 this key has to be set to the encoding used for the text + # parts of the kramdown document. + # + # :abbrev_defs:: This key may be used to store the mapping of abbreviation to abbreviation + # definition. + # + # :abbrev_attr:: This key may be used to store the mapping of abbreviation to abbreviation + # attributes. + # + # :options:: This key may be used to store options that were set during parsing of the document. + # + # :footnote_count:: This key stores the number of actually referenced footnotes of the document. + # + # === :blank + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Empty + # + # Represents one or more blank lines. It is not allowed to have two or more consecutive blank + # elements. + # + # The +value+ field may contain the original content of the blank lines. + # + # + # === :p + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Span-level elements + # + # Represents a paragraph. + # + # If the option :transparent is +true+, this element just represents a block of text. I.e. this + # element just functions as a container for span-level elements. + # + # + # === :header + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Span-level elements + # + # Represents a header. + # + # The option :level specifies the header level and has to contain a number between 1 and \6. The + # option :raw_text has to contain the raw header text. + # + # + # === :blockquote + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Block-level elements + # + # Represents a blockquote. + # + # + # === :codeblock + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Empty + # + # Represents a code block, i.e. a block of text that should be used as-is. + # + # The +value+ field has to contain the content of the code block. + # + # The option :lang specifies a highlighting language with possible HTML style options (e.g. + # php?start_inline=1) and should be used instead of a possibly also available language embedded in + # a class name of the form 'language-LANG'. + # + # + # === :ul + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] One or more :li elements + # + # Represents an unordered list. + # + # + # === :ol + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] One or more :li elements + # + # Represents an ordered list. + # + # + # === :li + # + # [Category] Block-level element + # [Usage context] Inside :ol and :ul elements + # [Content model] Block-level elements + # + # Represents a list item of an ordered or unordered list. + # + # Note that the first child of a list item must not be a :blank element! + # + # + # === :dl + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] One or more groups each consisting of one or more :dt elements followed by one + # or more :dd elements. + # + # Represents a definition list which contains groups consisting of terms and definitions for them. + # + # + # === :dt + # + # [Category] Block-level element + # [Usage context] Before :dt or :dd elements inside a :dl elment + # [Content model] Span-level elements + # + # Represents the term part of a term-definition group in a definition list. + # + # + # === :dd + # + # [Category] Block-level element + # [Usage context] After :dt or :dd elements inside a :dl elment + # [Content model] Block-level elements + # + # Represents the definition part of a term-definition group in a definition list. + # + # + # === :hr + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] None + # + # Represents a horizontal line. + # + # + # === :table + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Zero or one :thead elements, one or more :tbody elements, zero or one :tfoot + # elements + # + # Represents a table. Each table row (i.e. :tr element) of the table has to contain the same + # number of :td elements. + # + # The option :alignment has to be an array containing the alignment values, exactly one for each + # column of the table. The possible alignment values are :left, :center, :right and :default. + # + # + # === :thead + # + # [Category] None + # [Usage context] As first element inside a :table element + # [Content model] One or more :tr elements + # + # Represents the table header. + # + # + # === :tbody + # + # [Category] None + # [Usage context] After a :thead element but before a :tfoot element inside a :table element + # [Content model] One or more :tr elements + # + # Represents a table body. + # + # + # === :tfoot + # + # [Category] None + # [Usage context] As last element inside a :table element + # [Content model] One or more :tr elements + # + # Represents the table footer. + # + # + # === :tr + # + # [Category] None + # [Usage context] Inside :thead, :tbody and :tfoot elements + # [Content model] One or more :td elements + # + # Represents a table row. + # + # + # === :td + # + # [Category] Block-level element + # [Usage context] Inside :tr elements + # [Content model] As child of :thead/:tr span-level elements, as child of :tbody/:tr and + # :tfoot/:tr block-level elements + # + # Represents a table cell. + # + # + # === :math + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected + # [Content model] None + # + # Represents mathematical text that is written in LaTeX. + # + # The +value+ field has to contain the actual mathematical text. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. + # + # + # == Text Markup Elements + # + # === :text + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents text. + # + # The +value+ field has to contain the text itself. + # + # + # === :br + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a hard line break. + # + # + # === :a + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] Span-level elements + # + # Represents a link to an URL. + # + # The attribute +href+ has to be set to the URL to which the link points. The attribute +title+ + # optionally contains the title of the link. + # + # + # === :img + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents an image. + # + # The attribute +src+ has to be set to the URL of the image. The attribute +alt+ has to contain a + # text description of the image. The attribute +title+ optionally contains the title of the image. + # + # + # === :codespan + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents verbatim text. + # + # The +value+ field has to contain the content of the code span. + # + # + # === :footnote + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a footnote marker. + # + # The +value+ field has to contain an element whose children are the content of the footnote. The + # option :name has to contain a valid and unique footnote name. A valid footnote name consists of + # a word character or a digit and then optionally followed by other word characters, digits or + # dashes. + # + # + # === :em + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] Span-level elements + # + # Represents emphasis of its contents. + # + # + # === :strong + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] Span-level elements + # + # Represents strong importance for its contents. + # + # + # === :entity + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents an HTML entity. + # + # The +value+ field has to contain an instance of Kramdown::Utils::Entities::Entity. The option + # :original can be used to store the original representation of the entity. + # + # + # === :typographic_sym + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a typographic symbol. + # + # The +value+ field needs to contain a Symbol representing the specific typographic symbol from + # the following list: + # + # :mdash:: An mdash character (---) + # :ndash:: An ndash character (--) + # :hellip:: An ellipsis (...) + # :laquo:: A left guillemet (<<) + # :raquo:: A right guillemet (>>) + # :laquo_space:: A left guillemet with a space (<< ) + # :raquo_space:: A right guillemet with a space ( >>) + # + # + # === :smart_quote + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a quotation character. + # + # The +value+ field needs to contain a Symbol representing the specific quotation character: + # + # :lsquo:: Left single quote + # :rsquo:: Right single quote + # :ldquo:: Left double quote + # :rdquo:: Right double quote + # + # + # === :abbreviation + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a text part that is an abbreviation. + # + # The +value+ field has to contain the text part that is the abbreviation. The definition of the + # abbreviation is stored in the :root element of the document. + # + # + # == Other Elements + # + # === :html_element + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements or raw HTML elements are expected + # [Content model] Depends on the element + # + # Represents an HTML element. + # + # The +value+ field has to contain the name of the HTML element the element is representing. + # + # The option :category has to be set to either :span or :block depending on the whether the + # element is a block-level or a span-level element. The option :content_model has to be set to the + # content model for the element (either :block if it contains block-level elements, :span if it + # contains span-level elements or :raw if it contains raw content). + # + # + # === :xml_comment + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected or in raw HTML elements + # [Content model] None + # + # Represents an XML/HTML comment. + # + # The +value+ field has to contain the whole XML/HTML comment including the delimiters. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. + # + # + # === :xml_pi + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected or in raw HTML elements + # [Content model] None + # + # Represents an XML/HTML processing instruction. + # + # The +value+ field has to contain the whole XML/HTML processing instruction including the + # delimiters. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. + # + # + # === :comment + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected + # [Content model] None + # + # Represents a comment. + # + # The +value+ field has to contain the comment. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. If it is set to :span, then no blank lines are allowed in the comment. + # + # + # === :raw + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected + # [Content model] None + # + # Represents a raw string that should not be modified. For example, the element could contain some + # HTML code that should be output as-is without modification and escaping. + # + # The +value+ field has to contain the actual raw text. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. If it is set to :span, then no blank lines are allowed in the raw text. + # + # The option :type can be set to an array of strings to define for which converters the raw string + # is valid. + # + class Element + + # A symbol representing the element type. For example, :p or :blockquote. + attr_accessor :type + + # The value of the element. The interpretation of this field depends on the type of the element. + # Many elements don't use this field. + attr_accessor :value + + # The child elements of this element. + attr_accessor :children + + # Create a new Element object of type +type+. The optional parameters +value+, +attr+ and + # +options+ can also be set in this constructor for convenience. + def initialize(type, value = nil, attr = nil, options = nil) + @type, @value, @attr, @options = type, value, attr, options + @children = [] + end + + # The attributes of the element. + def attr + @attr ||= {} + end + + # The options hash for the element. It is used for storing arbitray options. + def options + @options ||= {} + end + + def inspect # :nodoc: + "<kd:#{@type}" \ + "#{value.nil? ? '' : ' value=' + value.inspect}" \ + "#{attr.empty? ? '' : ' attr=' + attr.inspect}" \ + "#{options.empty? ? '' : ' options=' + options.inspect}" \ + "#{children.empty? ? '' : ' children=' + children.inspect}>" + end + + CATEGORY = {} # :nodoc: + [:blank, :p, :header, :blockquote, :codeblock, :ul, :ol, :li, :dl, :dt, :dd, + :table, :td, :hr].each {|b| CATEGORY[b] = :block } + [:text, :a, :br, :img, :codespan, :footnote, :em, :strong, :entity, :typographic_sym, + :smart_quote, :abbreviation].each {|b| CATEGORY[b] = :span } + + # Return the category of +el+ which can be :block, :span or +nil+. + # + # Most elements have a fixed category, however, some elements can either appear in a block-level + # or a span-level context. These elements need to have the option :category correctly set. + def self.category(el) + CATEGORY[el.type] || el.options[:category] + end + + # syntactic sugar to simplify calls such as +Kramdown::Element.category(el) == :block+ with + # +el.block?+. + # + # Returns boolean true or false. + def block? + (CATEGORY[type] || options[:category]) == :block + end + + # syntactic sugar to simplify calls such as +Kramdown::Element.category(el) == :span+ with + # +el.span?+. + # + # Returns boolean true or false. + def span? + (CATEGORY[type] || options[:category]) == :span + end + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/error.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/error.rb new file mode 100644 index 0000000..81ffbc9 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/error.rb @@ -0,0 +1,17 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # This error is raised when an error condition is encountered. + # + # *Note* that this error is only raised by the support framework for the parsers and converters. + class Error < RuntimeError; end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/options.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/options.rb new file mode 100644 index 0000000..18d04e4 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/options.rb @@ -0,0 +1,645 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'yaml' + +module Kramdown + + # This module defines all options that are used by parsers and/or converters as well as providing + # methods to deal with the options. + module Options + + # Helper class introducing a boolean type for specifying boolean values (+true+ and +false+) as + # option types. + class Boolean + + # Return +true+ if +other+ is either +true+ or +false+ + def self.===(other) + FalseClass === other || TrueClass === other + end + + end + + # ---------------------------- + # :section: Option definitions + # + # This sections describes the methods that can be used on the Options module. + # ---------------------------- + + # Struct class for storing the definition of an option. + Definition = Struct.new(:name, :type, :default, :desc, :validator) + + # Allowed option types. + ALLOWED_TYPES = [String, Integer, Float, Symbol, Boolean, Object] + + @options = {} + @defaults = nil + + # Define a new option called +name+ (a Symbol) with the given +type+ (String, Integer, Float, + # Symbol, Boolean, Object), default value +default+ and the description +desc+. If a block is + # specified, it should validate the value and either raise an error or return a valid value. + # + # The type 'Object' should only be used for complex types for which none of the other types + # suffices. A block needs to be specified when using type 'Object' and it has to cope with + # a value given as string and as the opaque type. + def self.define(name, type, default, desc, &block) + name = name.to_sym + raise ArgumentError, "Option name #{name} is already used" if @options.key?(name) + raise ArgumentError, "Invalid option type #{type} specified" unless ALLOWED_TYPES.include?(type) + raise ArgumentError, "Invalid type for default value" if !(type === default) && !default.nil? + raise ArgumentError, "Missing validator block" if type == Object && block.nil? + @options[name] = Definition.new(name, type, default, desc, block) + @defaults = nil + end + + # Return all option definitions. + def self.definitions + @options + end + + # Return +true+ if an option called +name+ is defined. + def self.defined?(name) + @options.key?(name.to_sym) + end + + # Return a Hash with the default values for all options. + def self.defaults + @defaults ||= + begin + temp = {} + @options.each {|_n, o| temp[o.name] = o.default } + temp.freeze + end + end + + # Merge the #defaults Hash with the *parsed* options from the given Hash, i.e. only valid option + # names are considered and their value is run through the #parse method. + def self.merge(hash) + temp = defaults.dup + hash.each do |k, v| + k = k.to_sym + temp[k] = @options.key?(k) ? parse(k, v) : v + end + temp + end + + # Parse the given value +data+ as if it was a value for the option +name+ and return the parsed + # value with the correct type. + # + # If +data+ already has the correct type, it is just returned. Otherwise it is converted to a + # String and then to the correct type. + def self.parse(name, data) + name = name.to_sym + raise ArgumentError, "No option named #{name} defined" unless @options.key?(name) + unless @options[name].type === data + data = data.to_s + data = if @options[name].type == String + data + elsif @options[name].type == Integer + Integer(data) rescue raise Kramdown::Error, "Invalid integer value for option '#{name}': '#{data}'" + elsif @options[name].type == Float + Float(data) rescue raise Kramdown::Error, "Invalid float value for option '#{name}': '#{data}'" + elsif @options[name].type == Symbol + str_to_sym(data) + elsif @options[name].type == Boolean + data.downcase.strip != 'false' && !data.empty? + end + end + data = @options[name].validator[data] if @options[name].validator + data + end + + # Converts the given String +data+ into a Symbol or +nil+ with the + # following provisions: + # + # - A leading colon is stripped from the string. + # - An empty value or a value equal to "nil" results in +nil+. + def self.str_to_sym(data) + data = data.strip + data = data[1..-1] if data[0] == ':' + (data.empty? || data == 'nil' ? nil : data.to_sym) + end + + # ---------------------------- + # :section: Option Validators + # + # This sections contains all pre-defined option validators. + # ---------------------------- + + # Ensures that the option value +val+ for the option called +name+ is a valid array. The + # parameter +val+ can be + # + # - a comma separated string which is split into an array of values + # - or an array. + # + # Optionally, the array is checked for the correct size. + def self.simple_array_validator(val, name, size = nil) + if String === val + val = val.split(",") + elsif !(Array === val) + raise Kramdown::Error, "Invalid type #{val.class} for option #{name}" + end + if size && val.size != size + raise Kramdown::Error, "Option #{name} needs exactly #{size} values" + end + val + end + + # Ensures that the option value +val+ for the option called +name+ is a valid hash. The + # parameter +val+ can be + # + # - a hash in YAML format + # - or a Ruby Hash object. + def self.simple_hash_validator(val, name) + if String === val + begin + val = YAML.safe_load(val) + rescue RuntimeError, ArgumentError, SyntaxError + raise Kramdown::Error, "Invalid YAML value for option #{name}" + end + end + raise Kramdown::Error, "Invalid type #{val.class} for option #{name}" unless Hash === val + val + end + + # ---------------------------- + # :section: Option Definitions + # + # This sections contains all option definitions that are used by the included + # parsers/converters. + # ---------------------------- + + define(:template, String, '', <<~EOF) + The name of an ERB template file that should be used to wrap the output + or the ERB template itself. + + This is used to wrap the output in an environment so that the output can + be used as a stand-alone document. For example, an HTML template would + provide the needed header and body tags so that the whole output is a + valid HTML file. If no template is specified, the output will be just + the converted text. + + When resolving the template file, the given template name is used first. + If such a file is not found, the converter extension (the same as the + converter name) is appended. If the file still cannot be found, the + templates name is interpreted as a template name that is provided by + kramdown (without the converter extension). If the file is still not + found, the template name is checked if it starts with 'string://' and if + it does, this prefix is removed and the rest is used as template + content. + + kramdown provides a default template named 'document' for each converter. + + Default: '' + Used by: all converters + EOF + + define(:auto_ids, Boolean, true, <<~EOF) + Use automatic header ID generation + + If this option is `true`, ID values for all headers are automatically + generated if no ID is explicitly specified. + + Default: true + Used by: HTML/Latex converter + EOF + + define(:auto_id_stripping, Boolean, false, <<~EOF) + Strip all formatting from header text for automatic ID generation + + If this option is `true`, only the text elements of a header are used + for generating the ID later (in contrast to just using the raw header + text line). + + This option will be removed in version 2.0 because this will be the + default then. + + Default: false + Used by: kramdown parser + EOF + + define(:auto_id_prefix, String, '', <<~EOF) + Prefix used for automatically generated header IDs + + This option can be used to set a prefix for the automatically generated + header IDs so that there is no conflict when rendering multiple kramdown + documents into one output file separately. The prefix should only + contain characters that are valid in an ID! + + Default: '' + Used by: HTML/Latex converter + EOF + + define(:header_links, Boolean, false, <<~EOF) + Adds anchor tags within headers that can be used to generate permalinks + when not using a table of contents. + + The anchor tags are empty, but can be styled to your liking. + + Default: false + EOF + + define(:transliterated_header_ids, Boolean, false, <<~EOF) + Transliterate the header text before generating the ID + + Only ASCII characters are used in headers IDs. This is not good for + languages with many non-ASCII characters. By enabling this option + the header text is transliterated to ASCII as good as possible so that + the resulting header ID is more useful. + + The stringex library needs to be installed for this feature to work! + + Default: false + Used by: HTML/Latex converter + EOF + + define(:parse_block_html, Boolean, false, <<~EOF) + Process kramdown syntax in block HTML tags + + If this option is `true`, the kramdown parser processes the content of + block HTML tags as text containing block-level elements. Since this is + not wanted normally, the default is `false`. It is normally better to + selectively enable kramdown processing via the markdown attribute. + + Default: false + Used by: kramdown parser + EOF + + define(:parse_span_html, Boolean, true, <<~EOF) + Process kramdown syntax in span HTML tags + + If this option is `true`, the kramdown parser processes the content of + span HTML tags as text containing span-level elements. + + Default: true + Used by: kramdown parser + EOF + + define(:html_to_native, Boolean, false, <<~EOF) + Convert HTML elements to native elements + + If this option is `true`, the parser converts HTML elements to native + elements. For example, when parsing `<em>hallo</em>` the emphasis tag + would normally be converted to an `:html` element with tag type `:em`. + If `html_to_native` is `true`, then the emphasis would be converted to a + native `:em` element. + + This is useful for converters that cannot deal with HTML elements. + + Default: false + Used by: kramdown parser + EOF + + define(:link_defs, Object, {}, <<~EOF) do |val| + Pre-defines link definitions + + This option can be used to pre-define link definitions. The value needs + to be a Hash where the keys are the link identifiers and the values are + two element Arrays with the link URL and the link title. + + If the value is a String, it has to contain a valid YAML hash and the + hash has to follow the above guidelines. + + Default: {} + Used by: kramdown parser + EOF + val = simple_hash_validator(val, :link_defs) + val.each do |_k, v| + if !(Array === v) || v.size > 2 || v.empty? + raise Kramdown::Error, "Invalid structure for hash value of option #{name}" + end + v << nil if v.size == 1 + end + val + end + + define(:footnote_nr, Integer, 1, <<~EOF) + The number of the first footnote + + This option can be used to specify the number that is used for the first + footnote. + + Default: 1 + Used by: HTML converter + EOF + + define(:entity_output, Symbol, :as_char, <<~EOF) + Defines how entities are output + + The possible values are :as_input (entities are output in the same + form as found in the input), :numeric (entities are output in numeric + form), :symbolic (entities are output in symbolic form if possible) or + :as_char (entities are output as characters if possible, only available + on Ruby 1.9). + + Default: :as_char + Used by: HTML converter, kramdown converter + EOF + + TOC_LEVELS_RANGE = (1..6).freeze + TOC_LEVELS_ARRAY = TOC_LEVELS_RANGE.to_a.freeze + private_constant :TOC_LEVELS_RANGE, :TOC_LEVELS_ARRAY + + define(:toc_levels, Object, TOC_LEVELS_ARRAY, <<~EOF) do |val| + Defines the levels that are used for the table of contents + + The individual levels can be specified by separating them with commas + (e.g. 1,2,3) or by using the range syntax (e.g. 1..3). Only the + specified levels are used for the table of contents. + + Default: 1..6 + Used by: HTML/Latex converter + EOF + case val + when String + if val =~ /^(\d)\.\.(\d)$/ + val = Range.new($1.to_i, $2.to_i).to_a + elsif val.match?(/^\d(?:,\d)*$/) + val = val.split(",").map(&:to_i).uniq + else + raise Kramdown::Error, "Invalid syntax for option toc_levels" + end + when Array + unless val.eql?(TOC_LEVELS_ARRAY) + val = val.map(&:to_i).uniq + end + when Range + val = if val.eql?(TOC_LEVELS_RANGE) + TOC_LEVELS_ARRAY + else + val.map(&:to_i).uniq + end + else + raise Kramdown::Error, "Invalid type #{val.class} for option toc_levels" + end + if val.any? {|i| !TOC_LEVELS_RANGE.cover?(i) } + raise Kramdown::Error, "Level numbers for option toc_levels have to be integers from 1 to 6" + end + val + end + + define(:line_width, Integer, 72, <<~EOF) + Defines the line width to be used when outputting a document + + Default: 72 + Used by: kramdown converter + EOF + + define(:latex_headers, Object, %w[section subsection subsubsection paragraph subparagraph subparagraph], <<~EOF) do |val| + Defines the LaTeX commands for different header levels + + The commands for the header levels one to six can be specified by + separating them with commas. + + Default: section,subsection,subsubsection,paragraph,subparagraph,subparagraph + Used by: Latex converter + EOF + simple_array_validator(val, :latex_headers, 6) + end + + SMART_QUOTES_ENTITIES = %w[lsquo rsquo ldquo rdquo].freeze + SMART_QUOTES_STR = SMART_QUOTES_ENTITIES.join(',').freeze + private_constant :SMART_QUOTES_ENTITIES, :SMART_QUOTES_STR + + define(:smart_quotes, Object, SMART_QUOTES_ENTITIES, <<~EOF) do |val| + Defines the HTML entity names or code points for smart quote output + + The entities identified by entity name or code point that should be + used for, in order, a left single quote, a right single quote, a left + double and a right double quote are specified by separating them with + commas. + + Default: lsquo,rsquo,ldquo,rdquo + Used by: HTML/Latex converter + EOF + if val == SMART_QUOTES_STR || val == SMART_QUOTES_ENTITIES + SMART_QUOTES_ENTITIES + else + val = simple_array_validator(val, :smart_quotes, 4) + val.map! {|v| Integer(v) rescue v } + val + end + end + + define(:typographic_symbols, Object, {}, <<~EOF) do |val| + Defines a mapping from typographical symbol to output characters + + Typographical symbols are normally output using their equivalent Unicode + codepoint. However, sometimes one wants to change the output, mostly to + fallback to a sequence of ASCII characters. + + This option allows this by specifying a mapping from typographical + symbol to its output string. For example, the mapping {hellip: ...} would + output the standard ASCII representation of an ellipsis. + + The available typographical symbol names are: + + * hellip: ellipsis + * mdash: em-dash + * ndash: en-dash + * laquo: left guillemet + * raquo: right guillemet + * laquo_space: left guillemet followed by a space + * raquo_space: right guillemet preceeded by a space + + Default: {} + Used by: HTML/Latex converter + EOF + val = simple_hash_validator(val, :typographic_symbols) + val.keys.each do |k| + val[k.kind_of?(String) ? str_to_sym(k) : k] = val.delete(k).to_s + end + val + end + + define(:remove_block_html_tags, Boolean, true, <<~EOF) + Remove block HTML tags + + If this option is `true`, the RemoveHtmlTags converter removes + block HTML tags. + + Default: true + Used by: RemoveHtmlTags converter + EOF + + define(:remove_span_html_tags, Boolean, false, <<~EOF) + Remove span HTML tags + + If this option is `true`, the RemoveHtmlTags converter removes + span HTML tags. + + Default: false + Used by: RemoveHtmlTags converter + EOF + + define(:header_offset, Integer, 0, <<~EOF) + Sets the output offset for headers + + If this option is c (may also be negative) then a header with level n + will be output as a header with level c+n. If c+n is lower than 1, + level 1 will be used. If c+n is greater than 6, level 6 will be used. + + Default: 0 + Used by: HTML converter, Kramdown converter, Latex converter + EOF + + define(:syntax_highlighter, Symbol, :rouge, <<~EOF) + Set the syntax highlighter + + Specifies the syntax highlighter that should be used for highlighting + code blocks and spans. If this option is set to +nil+, no syntax + highlighting is done. + + Options for the syntax highlighter can be set with the + syntax_highlighter_opts configuration option. + + Default: rouge + Used by: HTML/Latex converter + EOF + + define(:syntax_highlighter_opts, Object, {}, <<~EOF) do |val| + Set the syntax highlighter options + + Specifies options for the syntax highlighter set via the + syntax_highlighter configuration option. + + The value needs to be a hash with key-value pairs that are understood by + the used syntax highlighter. + + Default: {} + Used by: HTML/Latex converter + EOF + val = simple_hash_validator(val, :syntax_highlighter_opts) + val.keys.each do |k| + val[k.kind_of?(String) ? str_to_sym(k) : k] = val.delete(k) + end + val + end + + define(:math_engine, Symbol, :mathjax, <<~EOF) + Set the math engine + + Specifies the math engine that should be used for converting math + blocks/spans. If this option is set to +nil+, no math engine is used and + the math blocks/spans are output as is. + + Options for the selected math engine can be set with the + math_engine_opts configuration option. + + Default: mathjax + Used by: HTML converter + EOF + + define(:math_engine_opts, Object, {}, <<~EOF) do |val| + Set the math engine options + + Specifies options for the math engine set via the math_engine + configuration option. + + The value needs to be a hash with key-value pairs that are understood by + the used math engine. + + Default: {} + Used by: HTML converter + EOF + val = simple_hash_validator(val, :math_engine_opts) + val.keys.each do |k| + val[k.kind_of?(String) ? str_to_sym(k) : k] = val.delete(k) + end + val + end + + define(:footnote_backlink, String, '↩', <<~EOF) + Defines the text that should be used for the footnote backlinks + + The footnote backlink is just text, so any special HTML characters will + be escaped. + + If the footnote backlint text is an empty string, no footnote backlinks + will be generated. + + Default: '&8617;' + Used by: HTML converter + EOF + + define(:footnote_backlink_inline, Boolean, false, <<~EOF) + Specifies whether the footnote backlink should always be inline + + With the default of false the footnote backlink is placed at the end of + the last paragraph if there is one, or an extra paragraph with only the + footnote backlink is created. + + Setting this option to true tries to place the footnote backlink in the + last, possibly nested paragraph or header. If this fails (e.g. in the + case of a table), an extra paragraph with only the footnote backlink is + created. + + Default: false + Used by: HTML converter + EOF + + define(:footnote_prefix, String, '', <<~EOF) + Prefix used for footnote IDs + + This option can be used to set a prefix for footnote IDs. This is useful + when rendering multiple documents into the same output file to avoid + duplicate IDs. The prefix should only contain characters that are valid + in an ID! + + Default: '' + Used by: HTML + EOF + + define(:footnote_link_text, String, '%s', <<~EOF) do |val| + The text used for the footnote number in a footnote link + + This option can be used to add additional text to the footnote + link. It should be a format string, and is passed the footnote + number as the only argument to the format string. + e.g. "[footnote %s]" would display as "[footnote 1]". + + Default: '%s' + Used by: HTML + EOF + if !val.include?('%s') + raise Kramdown::Error, "option footnote_link_text needs to contain a '%s'" + end + val + end + + + define(:remove_line_breaks_for_cjk, Boolean, false, <<~EOF) + Specifies whether line breaks should be removed between CJK characters + + Default: false + Used by: HTML converter + EOF + + define(:forbidden_inline_options, Object, %w[template], <<~EOF) do |val| + Defines the options that may not be set using the {::options} extension + + The value needs to be an array of option names. + + Default: [template] + Used by: HTML converter + EOF + val.map! {|item| item.kind_of?(String) ? str_to_sym(item) : item } + simple_array_validator(val, :forbidden_inline_options) + end + + define(:list_indent, Integer, 2, <<~EOF) + Sets the number of spaces to use for list indentation + + Default: 2 + Used by: Kramdown converter + EOF + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser.rb new file mode 100644 index 0000000..f77dcf6 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser.rb @@ -0,0 +1,26 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # This module contains all available parsers. A parser takes an input string and converts the + # string to an element tree. + # + # New parsers should be derived from the Base class which provides common functionality - see its + # API documentation for how to create a custom converter class. + module Parser + + autoload :Base, 'kramdown/parser/base' + autoload :Kramdown, 'kramdown/parser/kramdown' + autoload :Html, 'kramdown/parser/html' + autoload :Markdown, 'kramdown/parser/markdown' + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/base.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/base.rb new file mode 100644 index 0000000..298c974 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/base.rb @@ -0,0 +1,137 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/utils' +require 'kramdown/parser' + +module Kramdown + + module Parser + + # == \Base class for parsers + # + # This class serves as base class for parsers. It provides common methods that can/should be + # used by all parsers, especially by those using StringScanner(Kramdown) for parsing. + # + # A parser object is used as a throw-away object, i.e. it is only used for storing the needed + # state information during parsing. Therefore one can't instantiate a parser object directly but + # only use the Base::parse method. + # + # == Implementing a parser + # + # Implementing a new parser is rather easy: just derive a new class from this class and put it + # in the Kramdown::Parser module -- the latter is needed so that the auto-detection of the new + # parser works correctly. Then you need to implement the +#parse+ method which has to contain + # the parsing code. + # + # Have a look at the Base::parse, Base::new and Base#parse methods for additional information! + class Base + + # The hash with the parsing options. + attr_reader :options + + # The array with the parser warnings. + attr_reader :warnings + + # The original source string. + attr_reader :source + + # The root element of element tree that is created from the source string. + attr_reader :root + + # Initialize the parser object with the +source+ string and the parsing +options+. + # + # The @root element, the @warnings array and @text_type (specifies the default type for newly + # created text nodes) are automatically initialized. + def initialize(source, options) + @source = source + @options = Kramdown::Options.merge(options) + @root = Element.new(:root, nil, nil, encoding: (source.encoding rescue nil), location: 1, + options: {}, abbrev_defs: {}, abbrev_attr: {}) + + @root.options[:abbrev_defs].default_proc = @root.options[:abbrev_attr].default_proc = + lambda do |h, k| + k_mod = k.gsub(/[\s\p{Z}]+/, " ") + k != k_mod ? h[k_mod] : nil + end + @warnings = [] + @text_type = :text + end + private_class_method(:new, :allocate) + + # Parse the +source+ string into an element tree, possibly using the parsing +options+, and + # return the root element of the element tree and an array with warning messages. + # + # Initializes a new instance of the calling class and then calls the +#parse+ method that must + # be implemented by each subclass. + def self.parse(source, options = {}) + parser = new(source, options) + parser.parse + [parser.root, parser.warnings] + end + + # Parse the source string into an element tree. + # + # The parsing code should parse the source provided in @source and build an element tree the + # root of which should be @root. + # + # This is the only method that has to be implemented by sub-classes! + def parse + raise NotImplementedError + end + + # Add the given warning +text+ to the warning array. + def warning(text) + @warnings << text + # TODO: add position information + end + + # Modify the string +source+ to be usable by the parser (unifies line ending characters to + # +\n+ and makes sure +source+ ends with a new line character). + def adapt_source(source) + unless source.valid_encoding? + raise "The source text contains invalid characters for the used encoding #{source.encoding}" + end + source = source.encode('UTF-8') + source.gsub!(/\r\n?/, "\n") + source.chomp! + source << "\n" + end + + # This helper method adds the given +text+ either to the last element in the +tree+ if it is a + # +type+ element or creates a new text element with the given +type+. + def add_text(text, tree = @tree, type = @text_type) + last = tree.children.last + if last && last.type == type + last.value << text + elsif !text.empty? + location = (last && last.options[:location] || tree.options[:location]) + tree.children << Element.new(type, text, nil, location: location) + end + end + + # Extract the part of the StringScanner +strscan+ backed string specified by the +range+. This + # method works correctly under Ruby 1.8 and Ruby 1.9. + def extract_string(range, strscan) + result = nil + begin + enc = strscan.string.encoding + strscan.string.force_encoding('ASCII-8BIT') + result = strscan.string[range].force_encoding(enc) + ensure + strscan.string.force_encoding(enc) + end + result + end + + end + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/html.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/html.rb new file mode 100644 index 0000000..2c99fdc --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/html.rb @@ -0,0 +1,621 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'rexml/parsers/baseparser' +require 'strscan' +require 'kramdown/utils' +require 'kramdown/parser' + +module Kramdown + + module Parser + + # Used for parsing an HTML document. + # + # The parsing code is in the Parser module that can also be used by other parsers. + class Html < Base + + # Contains all constants that are used when parsing. + module Constants + + # :stopdoc: + # The following regexps are based on the ones used by REXML, with some slight modifications. + HTML_DOCTYPE_RE = /<!DOCTYPE.*?>/im + HTML_COMMENT_RE = /<!--(.*?)-->/m + HTML_INSTRUCTION_RE = /<\?(.*?)\?>/m + HTML_CDATA_RE = /<!\[CDATA\[(.*?)\]\]>/m + HTML_ATTRIBUTE_RE = /\s*(#{REXML::Parsers::BaseParser::UNAME_STR})(?:\s*=\s*(?:(\p{Word}+)|("|')(.*?)\3))?/m + HTML_TAG_RE = /<((?>#{REXML::Parsers::BaseParser::UNAME_STR}))\s*((?>\s+#{REXML::Parsers::BaseParser::UNAME_STR}(?:\s*=\s*(?:\p{Word}+|("|').*?\3))?)*)\s*(\/)?>/m + HTML_TAG_CLOSE_RE = /<\/(#{REXML::Parsers::BaseParser::UNAME_STR})\s*>/m + HTML_ENTITY_RE = /&([\w:][\w.:-]*);|&#(\d+);|&\#x([0-9a-fA-F]+);/ + + HTML_CONTENT_MODEL_BLOCK = %w[address applet article aside blockquote body + dd details div dl fieldset figure figcaption + footer form header hgroup iframe li main + map menu nav noscript object section summary td] + HTML_CONTENT_MODEL_SPAN = %w[a abbr acronym b bdo big button cite caption del dfn dt em + h1 h2 h3 h4 h5 h6 i ins label legend optgroup p q rb rbc + rp rt rtc ruby select small span strong sub sup th tt] + HTML_CONTENT_MODEL_RAW = %w[script style math option textarea pre code kbd samp var] + # The following elements are also parsed as raw since they need child elements that cannot + # be expressed using kramdown syntax: colgroup table tbody thead tfoot tr ul ol + + HTML_CONTENT_MODEL = Hash.new {|h, k| h[k] = :raw } + HTML_CONTENT_MODEL_BLOCK.each {|i| HTML_CONTENT_MODEL[i] = :block } + HTML_CONTENT_MODEL_SPAN.each {|i| HTML_CONTENT_MODEL[i] = :span } + HTML_CONTENT_MODEL_RAW.each {|i| HTML_CONTENT_MODEL[i] = :raw } + + # Some HTML elements like script belong to both categories (i.e. are valid in block and + # span HTML) and don't appear therefore! + # script, textarea + HTML_SPAN_ELEMENTS = %w[a abbr acronym b big bdo br button cite code del dfn em i img input + ins kbd label mark option q rb rbc rp rt rtc ruby samp select small + span strong sub sup time tt u var] + HTML_BLOCK_ELEMENTS = %w[address article aside applet body blockquote caption col colgroup + dd div dl dt fieldset figcaption footer form h1 h2 h3 h4 h5 h6 + header hgroup hr html head iframe legend menu li main map nav ol + optgroup p pre section summary table tbody td th thead tfoot tr ul] + HTML_ELEMENTS_WITHOUT_BODY = %w[area base br col command embed hr img input keygen link + meta param source track wbr] + + HTML_ELEMENT = Hash.new(false) + (HTML_SPAN_ELEMENTS + HTML_BLOCK_ELEMENTS + HTML_ELEMENTS_WITHOUT_BODY + + HTML_CONTENT_MODEL.keys).each do |a| + HTML_ELEMENT[a] = true + end + end + + # Contains the parsing methods. This module can be mixed into any parser to get HTML parsing + # functionality. The only thing that must be provided by the class are instance variable + # @stack for storing the needed state and @src (instance of StringScanner) for the actual + # parsing. + module Parser + + include Constants + + # Process the HTML start tag that has already be scanned/checked via @src. + # + # Does the common processing steps and then yields to the caller for further processing + # (first parameter is the created element; the second parameter is +true+ if the HTML + # element is already closed, ie. contains no body; the third parameter specifies whether the + # body - and the end tag - need to be handled in case closed=false). + def handle_html_start_tag(line = nil) # :yields: el, closed, handle_body + name = @src[1] + name.downcase! if HTML_ELEMENT[name.downcase] + closed = !@src[4].nil? + attrs = parse_html_attributes(@src[2], line, HTML_ELEMENT[name]) + + el = Element.new(:html_element, name, attrs, category: :block) + el.options[:location] = line if line + @tree.children << el + + if !closed && HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) + closed = true + end + if name == 'script' || name == 'style' + handle_raw_html_tag(name) + yield(el, false, false) + else + yield(el, closed, true) + end + end + + # Parses the given string for HTML attributes and returns the resulting hash. + # + # If the optional +line+ parameter is supplied, it is used in warning messages. + # + # If the optional +in_html_tag+ parameter is set to +false+, attributes are not modified to + # contain only lowercase letters. + def parse_html_attributes(str, line = nil, in_html_tag = true) + attrs = {} + str.scan(HTML_ATTRIBUTE_RE).each do |attr, val, _sep, quoted_val| + attr.downcase! if in_html_tag + if attrs.key?(attr) + warning("Duplicate HTML attribute '#{attr}' on line #{line || '?'} - overwriting previous one") + end + attrs[attr] = val || quoted_val || "" + end + attrs + end + + # Handle the raw HTML tag at the current position. + def handle_raw_html_tag(name) + curpos = @src.pos + if @src.scan_until(/(?=<\/#{name}\s*>)/mi) + add_text(extract_string(curpos...@src.pos, @src), @tree.children.last, :raw) + @src.scan(HTML_TAG_CLOSE_RE) + else + add_text(@src.rest, @tree.children.last, :raw) + @src.terminate + warning("Found no end tag for '#{name}' - auto-closing it") + end + end + + HTML_RAW_START = /(?=<(#{REXML::Parsers::BaseParser::UNAME_STR}|\/|!--|\?|!\[CDATA\[))/ # :nodoc: + + # Parse raw HTML from the current source position, storing the found elements in +el+. + # Parsing continues until one of the following criteria are fulfilled: + # + # - The end of the document is reached. + # - The matching end tag for the element +el+ is found (only used if +el+ is an HTML + # element). + # + # When an HTML start tag is found, processing is deferred to #handle_html_start_tag, + # providing the block given to this method. + def parse_raw_html(el, &block) + @stack.push(@tree) + @tree = el + + done = false + while !@src.eos? && !done + if (result = @src.scan_until(HTML_RAW_START)) + add_text(result, @tree, :text) + line = @src.current_line_number + if (result = @src.scan(HTML_COMMENT_RE)) + @tree.children << Element.new(:xml_comment, result, nil, category: :block, location: line) + elsif (result = @src.scan(HTML_INSTRUCTION_RE)) + @tree.children << Element.new(:xml_pi, result, nil, category: :block, location: line) + elsif @src.scan(HTML_CDATA_RE) + @tree.children << Element.new(:text, @src[1], nil, cdata: true, location: line) + elsif @src.scan(HTML_TAG_RE) + if method(:handle_html_start_tag).arity.abs >= 1 + handle_html_start_tag(line, &block) + else + handle_html_start_tag(&block) # DEPRECATED: method needs to accept line number in 2.0 + end + elsif @src.scan(HTML_TAG_CLOSE_RE) + if @tree.value == (HTML_ELEMENT[@tree.value] ? @src[1].downcase : @src[1]) + done = true + else + add_text(@src.matched, @tree, :text) + warning("Found invalidly used HTML closing tag for '#{@src[1]}' on " \ + "line #{line} - ignoring it") + end + else + add_text(@src.getch, @tree, :text) + end + else + add_text(@src.rest, @tree, :text) + @src.terminate + if @tree.type == :html_element + warning("Found no end tag for '#{@tree.value}' on line " \ + "#{@tree.options[:location]} - auto-closing it") + end + done = true + end + end + + @tree = @stack.pop + end + + end + + # Converts HTML elements to native elements if possible. + class ElementConverter + + # :stopdoc: + + include Constants + include ::Kramdown::Utils::Entities + + REMOVE_TEXT_CHILDREN = %w[html head hgroup ol ul dl table colgroup tbody thead tfoot tr + select optgroup] + WRAP_TEXT_CHILDREN = %w[body section nav article aside header footer address div li dd + blockquote figure figcaption fieldset form] + REMOVE_WHITESPACE_CHILDREN = %w[body section nav article aside header footer address + div li dd blockquote figure figcaption td th fieldset form] + STRIP_WHITESPACE = %w[address article aside blockquote body caption dd div dl dt fieldset + figcaption form footer header h1 h2 h3 h4 h5 h6 legend li nav p + section td th] + SIMPLE_ELEMENTS = %w[em strong blockquote hr br img p thead tbody tfoot tr td th ul ol dl + li dl dt dd] + + def initialize(root) + @root = root + end + + def self.convert(root, el = root) + new(root).process(el) + end + + # Convert the element +el+ and its children. + def process(el, do_conversion = true, preserve_text = false, parent = nil) + case el.type + when :xml_comment, :xml_pi + ptype = if parent.nil? + 'div' + else + case parent.type + when :html_element then parent.value + when :code_span then 'code' + when :code_block then 'pre' + when :header then 'h1' + else parent.type.to_s + end + end + el.options.replace(category: (HTML_CONTENT_MODEL[ptype] == :span ? :span : :block)) + return + when :html_element + # do nothing + when :root + el.children.map! do |c| + if c.type == :text + process_text(c.value, !do_conversion) + else + process(c) + c + end + end.flatten! + remove_whitespace_children(el) + return + else return + end + + mname = "convert_#{el.value}" + if do_conversion && self.class.method_defined?(mname) + send(mname, el) + else + type = el.value + remove_text_children(el) if do_conversion && REMOVE_TEXT_CHILDREN.include?(type) + + if do_conversion && SIMPLE_ELEMENTS.include?(type) + set_basics(el, type.intern) + process_children(el, do_conversion, preserve_text) + else + process_html_element(el, do_conversion, preserve_text) + end + + if do_conversion + strip_whitespace(el) if STRIP_WHITESPACE.include?(type) + remove_whitespace_children(el) if REMOVE_WHITESPACE_CHILDREN.include?(type) + wrap_text_children(el) if WRAP_TEXT_CHILDREN.include?(type) + end + end + end + + def process_children(el, do_conversion = true, preserve_text = false) + el.children.map! do |c| + if c.type == :text + process_text(c.value, preserve_text || !do_conversion) + else + process(c, do_conversion, preserve_text, el) + c + end + end.flatten! + end + + # Process the HTML text +raw+: compress whitespace (if +preserve+ is +false+) and convert + # entities in entity elements. + def process_text(raw, preserve = false) + raw.gsub!(/\s+/, ' ') unless preserve + src = Kramdown::Utils::StringScanner.new(raw) + result = [] + until src.eos? + if (tmp = src.scan_until(/(?=#{HTML_ENTITY_RE})/o)) + result << Element.new(:text, tmp) + src.scan(HTML_ENTITY_RE) + val = src[1] || src[2]&.to_i || src[3].hex + result << if %w[lsquo rsquo ldquo rdquo].include?(val) + Element.new(:smart_quote, val.intern) + elsif %w[mdash ndash hellip laquo raquo].include?(val) + Element.new(:typographic_sym, val.intern) + else + begin + Element.new(:entity, entity(val), nil, original: src.matched) + rescue ::Kramdown::Error + src.pos -= src.matched_size - 1 + Element.new(:entity, ::Kramdown::Utils::Entities.entity('amp')) + end + end + else + result << Element.new(:text, src.rest) + src.terminate + end + end + result + end + + def process_html_element(el, do_conversion = true, preserve_text = false) + el.options.replace(category: HTML_SPAN_ELEMENTS.include?(el.value) ? :span : :block, + content_model: (do_conversion ? HTML_CONTENT_MODEL[el.value] : :raw)) + process_children(el, do_conversion, preserve_text) + end + + def remove_text_children(el) + el.children.delete_if {|c| c.type == :text } + end + + def wrap_text_children(el) + tmp = [] + last_is_p = false + el.children.each do |c| + if !c.block? || c.type == :text + unless last_is_p + tmp << Element.new(:p, nil, nil, transparent: true) + last_is_p = true + end + tmp.last.children << c + tmp + else + tmp << c + last_is_p = false + end + end + el.children = tmp + end + + def strip_whitespace(el) + return if el.children.empty? + if el.children.first.type == :text + el.children.first.value.lstrip! + end + if el.children.last.type == :text + el.children.last.value.rstrip! + end + end + + def remove_whitespace_children(el) + i = -1 + el.children = el.children.reject do |c| + i += 1 + c.type == :text && c.value.strip.empty? && + (i == 0 || i == el.children.length - 1 || (el.children[i - 1].block? && + el.children[i + 1].block?)) + end + end + + def set_basics(el, type, opts = {}) + el.type = type + el.options.replace(opts) + el.value = nil + end + + def extract_text(el, raw) + raw << el.value.to_s if el.type == :text + el.children.each {|c| extract_text(c, raw) } + end + + def convert_textarea(el) + process_html_element(el, true, true) + end + + def convert_a(el) + if el.attr['href'] + set_basics(el, :a) + process_children(el) + else + process_html_element(el, false) + end + end + + EMPHASIS_TYPE_MAP = {'em' => :em, 'i' => :em, 'strong' => :strong, 'b' => :strong} + def convert_em(el) + text = +'' + extract_text(el, text) + if text =~ /\A\s/ || text =~ /\s\z/ + process_html_element(el, false) + else + set_basics(el, EMPHASIS_TYPE_MAP[el.value]) + process_children(el) + end + end + %w[b strong i].each do |i| + alias_method("convert_#{i}".to_sym, :convert_em) + end + + def convert_h1(el) + set_basics(el, :header, level: el.value[1..1].to_i) + extract_text(el, el.options[:raw_text] = +'') + process_children(el) + end + %w[h2 h3 h4 h5 h6].each do |i| + alias_method("convert_#{i}".to_sym, :convert_h1) + end + + def convert_code(el) + raw = +'' + extract_text(el, raw) + result = process_text(raw, true) + begin + str = result.inject(+'') do |mem, c| + case c.type + when :text + mem << c.value + when :entity + mem << if [60, 62, 34, 38].include?(c.value.code_point) + c.value.code_point.chr + else + c.value.char + end + when :smart_quote, :typographic_sym + mem << entity(c.value.to_s).char + else + raise "Bug - please report" + end + end + result.clear + result << Element.new(:text, str) + rescue StandardError + end + if result.length > 1 || result.first.type != :text + process_html_element(el, false, true) + else + if el.value == 'code' + set_basics(el, :codespan) + el.attr['class']&.gsub!(/\s+\bhighlighter-\w+\b|\bhighlighter-\w+\b\s*/, '') + else + set_basics(el, :codeblock) + if el.children.size == 1 && el.children.first.value == 'code' + value = (el.children.first.attr['class'] || '').scan(/\blanguage-\S+/).first + el.attr['class'] = "#{value} #{el.attr['class']}".rstrip if value + end + end + el.value = result.first.value + el.children.clear + end + end + alias convert_pre convert_code + + def convert_table(el) + unless is_simple_table?(el) + process_html_element(el, false) + return + end + remove_text_children(el) + process_children(el) + set_basics(el, :table) + + calc_alignment = lambda do |c| + if c.type == :tr + el.options[:alignment] = c.children.map do |td| + if td.attr['style'] + td.attr['style'].slice!(/(?:;\s*)?text-align:\s+(center|left|right)/) + td.attr.delete('style') if td.attr['style'].strip.empty? + $1 ? $1.to_sym : :default + else + :default + end + end + else + c.children.each {|cc| calc_alignment.call(cc) } + end + end + calc_alignment.call(el) + el.children.delete_if {|c| c.type == :html_element } + + change_th_type = lambda do |c| + if c.type == :th + c.type = :td + else + c.children.each {|cc| change_th_type.call(cc) } + end + end + change_th_type.call(el) + + if el.children.first.type == :tr + tbody = Element.new(:tbody) + tbody.children = el.children + el.children = [tbody] + end + end + + def is_simple_table?(el) + only_phrasing_content = lambda do |c| + c.children.all? do |cc| + (cc.type == :text || !HTML_BLOCK_ELEMENTS.include?(cc.value)) && only_phrasing_content.call(cc) + end + end + check_cells = proc do |c| + if c.value == 'th' || c.value == 'td' + return false unless only_phrasing_content.call(c) + else + c.children.each {|cc| check_cells.call(cc) } + end + end + check_cells.call(el) + + nr_cells = 0 + check_nr_cells = lambda do |t| + if t.value == 'tr' + count = t.children.count {|cc| cc.value == 'th' || cc.value == 'td' } + if count != nr_cells + if nr_cells == 0 + nr_cells = count + else + nr_cells = -1 + break + end + end + else + t.children.each {|cc| check_nr_cells.call(cc) } + end + end + check_nr_cells.call(el) + return false if nr_cells == -1 || nr_cells == 0 + + alignment = nil + check_alignment = proc do |t| + if t.value == 'tr' + cur_alignment = t.children.select {|cc| cc.value == 'th' || cc.value == 'td' }.map do |cell| + md = /text-align:\s+(center|left|right|justify|inherit)/.match(cell.attr['style'].to_s) + return false if md && (md[1] == 'justify' || md[1] == 'inherit') + md.nil? ? :default : md[1] + end + alignment = cur_alignment if alignment.nil? + return false if alignment != cur_alignment + else + t.children.each {|cc| check_alignment.call(cc) } + end + end + check_alignment.call(el) + + check_rows = lambda do |t, type| + t.children.all? do |r| + (r.value == 'tr' || r.type == :text) && r.children.all? {|c| c.value == type || c.type == :text } + end + end + check_rows.call(el, 'td') || + (el.children.all? do |t| + t.type == :text || (t.value == 'thead' && check_rows.call(t, 'th')) || + ((t.value == 'tfoot' || t.value == 'tbody') && check_rows.call(t, 'td')) + end && el.children.any? {|t| t.value == 'tbody' }) + end + + def convert_script(el) + if is_math_tag?(el) + handle_math_tag(el) + else + process_html_element(el) + end + end + + def is_math_tag?(el) + el.attr['type'].to_s =~ /\bmath\/tex\b/ + end + + def handle_math_tag(el) + set_basics(el, :math, category: (el.attr['type'].include?("mode=display") ? :block : :span)) + el.value = el.children.shift.value.sub(/\A(?:%\s*)?<!\[CDATA\[\n?(.*?)(?:\s%)?\]\]>\z/m, '\1') + el.attr.delete('type') + end + + end + + include Parser + + # Parse the source string provided on initialization as HTML document. + def parse + @stack, @tree = [], @root + @src = Kramdown::Utils::StringScanner.new(adapt_source(source)) + + while true + if (result = @src.scan(/\s*#{HTML_INSTRUCTION_RE}/o)) + @tree.children << Element.new(:xml_pi, result.strip, nil, category: :block) + elsif (result = @src.scan(/\s*#{HTML_DOCTYPE_RE}/o)) + # ignore the doctype + elsif (result = @src.scan(/\s*#{HTML_COMMENT_RE}/o)) + @tree.children << Element.new(:xml_comment, result.strip, nil, category: :block) + else + break + end + end + + tag_handler = lambda do |c, closed, handle_body| + parse_raw_html(c, &tag_handler) if !closed && handle_body + end + parse_raw_html(@tree, &tag_handler) + + ElementConverter.convert(@tree) + end + + end + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown.rb new file mode 100644 index 0000000..a8f480b --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown.rb @@ -0,0 +1,377 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'strscan' +require 'stringio' +require 'kramdown/parser' + +# TODO: use [[:alpha:]] in all regexp to allow parsing of international values in 1.9.1 +# NOTE: use @src.pre_match only before other check/match?/... operations, otherwise the content is changed + +module Kramdown + + module Parser + + # Used for parsing a document in kramdown format. + # + # If you want to extend the functionality of the parser, you need to do the following: + # + # * Create a new subclass + # * add the needed parser methods + # * modify the @block_parsers and @span_parsers variables and add the names of your parser + # methods + # + # Here is a small example for an extended parser class that parses ERB style tags as raw text if + # they are used as span-level elements (an equivalent block-level parser should probably also be + # made to handle the block case): + # + # require 'kramdown/parser/kramdown' + # + # class Kramdown::Parser::ERBKramdown < Kramdown::Parser::Kramdown + # + # def initialize(source, options) + # super + # @span_parsers.unshift(:erb_tags) + # end + # + # ERB_TAGS_START = /<%.*?%>/ + # + # def parse_erb_tags + # @src.pos += @src.matched_size + # @tree.children << Element.new(:raw, @src.matched) + # end + # define_parser(:erb_tags, ERB_TAGS_START, '<%') + # + # end + # + # The new parser can be used like this: + # + # require 'kramdown/document' + # # require the file with the above parser class + # + # Kramdown::Document.new(input_text, :input => 'ERBKramdown').to_html + # + class Kramdown < Base + + include ::Kramdown + + # Create a new Kramdown parser object with the given +options+. + def initialize(source, options) + super + + reset_env + + @alds = {} + @footnotes = {} + @link_defs = {} + update_link_definitions(@options[:link_defs]) + + @block_parsers = [:blank_line, :codeblock, :codeblock_fenced, :blockquote, :atx_header, + :horizontal_rule, :list, :definition_list, :block_html, :setext_header, + :block_math, :table, :footnote_definition, :link_definition, + :abbrev_definition, :block_extensions, :eob_marker, :paragraph] + @span_parsers = [:emphasis, :codespan, :autolink, :span_html, :footnote_marker, :link, + :smart_quotes, :inline_math, :span_extensions, :html_entity, + :typographic_syms, :line_break, :escaped_chars] + + @span_pattern_cache ||= Hash.new {|h, k| h[k] = {} } + end + private_class_method(:new, :allocate) + + # The source string provided on initialization is parsed into the @root element. + def parse + configure_parser + parse_blocks(@root, adapt_source(source)) + update_tree(@root) + correct_abbreviations_attributes + replace_abbreviations(@root) + @footnotes.each do |_name, data| + update_tree(data[:content]) + replace_abbreviations(data[:content]) + end + footnote_count = 0 + @footnotes.each do |name, data| + (footnote_count += 1; next) if data.key?(:marker) + line = data[:content].options[:location] + warning("Footnote definition for '#{name}' on line #{line} is unreferenced - ignoring") + end + @root.options[:footnote_count] = footnote_count + end + + protected + + # :doc: + # + # Update the parser specific link definitions with the data from +link_defs+ (the value of the + # :link_defs option). + # + # The parameter +link_defs+ is a hash where the keys are possibly unnormalized link IDs and + # the values are two element arrays consisting of the link target and a title (can be +nil+). + def update_link_definitions(link_defs) + link_defs.each {|k, v| @link_defs[normalize_link_id(k)] = v } + end + + # Adapt the object to allow parsing like specified in the options. + def configure_parser + @parsers = {} + (@block_parsers + @span_parsers).each do |name| + if self.class.has_parser?(name) + @parsers[name] = self.class.parser(name) + else + raise Kramdown::Error, "Unknown parser: #{name}" + end + end + @span_start, @span_start_re = span_parser_regexps + end + + # Create the needed span parser regexps. + def span_parser_regexps(parsers = @span_parsers) + span_start = /#{parsers.map {|name| @parsers[name].span_start }.join('|')}/ + [span_start, /(?=#{span_start})/] + end + + # Parse all block-level elements in +text+ into the element +el+. + def parse_blocks(el, text = nil) + @stack.push([@tree, @src, @block_ial]) + @tree, @block_ial = el, nil + @src = (text.nil? ? @src : ::Kramdown::Utils::StringScanner.new(text, el.options[:location])) + + status = catch(:stop_block_parsing) do + until @src.eos? + @block_parsers.any? do |name| + if @src.check(@parsers[name].start_re) + send(@parsers[name].method) + else + false + end + end || begin + warning('Warning: this should not occur - no block parser handled the line') + add_text(@src.scan(/.*\n/)) + end + end + end + + @tree, @src, @block_ial = *@stack.pop + status + end + + # Update the tree by parsing all :+raw_text+ elements with the span-level parser (resets the + # environment) and by updating the attributes from the IALs. + def update_tree(element) + last_blank = nil + element.children.map! do |child| + case child.type + when :raw_text + last_blank = nil + reset_env(src: ::Kramdown::Utils::StringScanner.new(child.value, element.options[:location]), + text_type: :text) + parse_spans(child) + child.children + when :eob + update_attr_with_ial(child.attr, child.options[:ial]) if child.options[:ial] + [] + when :blank + if last_blank + last_blank.value << child.value + [] + else + last_blank = child + child + end + else + last_blank = nil + update_tree(child) + update_attr_with_ial(child.attr, child.options[:ial]) if child.options[:ial] + # DEPRECATED: option auto_id_stripping will be removed in 2.0 because then this will be + # the default behaviour + if child.type == :dt || (child.type == :header && @options[:auto_id_stripping]) + update_raw_text(child) + end + child + end + end.flatten! + end + + def span_pattern_cache(stop_re, span_start) + @span_pattern_cache[stop_re][span_start] ||= /(?=#{Regexp.union(stop_re, span_start)})/ + end + private :span_pattern_cache + + # Parse all span-level elements in the source string of @src into +el+. + # + # If the parameter +stop_re+ (a regexp) is used, parsing is immediately stopped if the regexp + # matches and if no block is given or if a block is given and it returns +true+. + # + # The parameter +parsers+ can be used to specify the (span-level) parsing methods that should + # be used for parsing. + # + # The parameter +text_type+ specifies the type which should be used for created text nodes. + def parse_spans(el, stop_re = nil, parsers = nil, text_type = @text_type) + @stack.push([@tree, @text_type]) unless @tree.nil? + @tree, @text_type = el, text_type + + span_start = @span_start + span_start_re = @span_start_re + span_start, span_start_re = span_parser_regexps(parsers) if parsers + parsers ||= @span_parsers + + used_re = (stop_re.nil? ? span_start_re : span_pattern_cache(stop_re, span_start)) + stop_re_found = false + while !@src.eos? && !stop_re_found + if (result = @src.scan_until(used_re)) + add_text(result) + if stop_re && @src.check(stop_re) + stop_re_found = (block_given? ? yield : true) + end + processed = parsers.any? do |name| + if @src.check(@parsers[name].start_re) + send(@parsers[name].method) + true + else + false + end + end unless stop_re_found + add_text(@src.getch) if !processed && !stop_re_found + else + (add_text(@src.rest); @src.terminate) unless stop_re + break + end + end + + @tree, @text_type = @stack.pop + + stop_re_found + end + + # Reset the current parsing environment. The parameter +env+ can be used to set initial + # values for one or more environment variables. + def reset_env(opts = {}) + opts = {text_type: :raw_text, stack: []}.merge(opts) + @src = opts[:src] + @tree = opts[:tree] + @block_ial = opts[:block_ial] + @stack = opts[:stack] + @text_type = opts[:text_type] + end + + # Return the current parsing environment. + def save_env + [@src, @tree, @block_ial, @stack, @text_type] + end + + # Restore the current parsing environment. + def restore_env(env) + @src, @tree, @block_ial, @stack, @text_type = *env + end + + # Update the given attributes hash +attr+ with the information from the inline attribute list + # +ial+ and all referenced ALDs. + def update_attr_with_ial(attr, ial) + ial[:refs]&.each do |ref| + update_attr_with_ial(attr, ref) if (ref = @alds[ref]) + end + ial.each do |k, v| + if k == IAL_CLASS_ATTR + attr[k] = "#{attr[k]} #{v}".lstrip + elsif k.kind_of?(String) + attr[k] = v + end + end + end + + # Update the raw text for automatic ID generation. + def update_raw_text(item) + raw_text = +'' + + append_text = lambda do |child| + if child.type == :text + raw_text << child.value + else + child.children.each {|c| append_text.call(c) } + end + end + + append_text.call(item) + item.options[:raw_text] = raw_text + end + + # Create a new block-level element, taking care of applying a preceding block IAL if it + # exists. This method should always be used for creating a block-level element! + def new_block_el(*args) + el = Element.new(*args) + if @block_ial + el.options[:ial] = @block_ial + @block_ial = nil + end + el + end + + @@parsers = {} + + # Struct class holding all the needed data for one block/span-level parser method. + Data = Struct.new(:name, :start_re, :span_start, :method) + + # Add a parser method + # + # * with the given +name+, + # * using +start_re+ as start regexp + # * and, for span parsers, +span_start+ as a String that can be used in a regexp and + # which identifies the starting character(s) + # + # to the registry. The method name is automatically derived from the +name+ or can explicitly + # be set by using the +meth_name+ parameter. + def self.define_parser(name, start_re, span_start = nil, meth_name = "parse_#{name}") + raise "A parser with the name #{name} already exists!" if @@parsers.key?(name) + @@parsers[name] = Data.new(name, start_re, span_start, meth_name) + end + + # Return the Data structure for the parser +name+. + def self.parser(name = nil) + @@parsers[name] + end + + # Return +true+ if there is a parser called +name+. + def self.has_parser?(name) + @@parsers.key?(name) + end + + # Regexp for matching indentation (one tab or four spaces) + INDENT = /^(?:\t| {4})/ + # Regexp for matching the optional space (zero or up to three spaces) + OPT_SPACE = / {0,3}/ + + require 'kramdown/parser/kramdown/blank_line' + require 'kramdown/parser/kramdown/eob' + require 'kramdown/parser/kramdown/paragraph' + require 'kramdown/parser/kramdown/header' + require 'kramdown/parser/kramdown/blockquote' + require 'kramdown/parser/kramdown/table' + require 'kramdown/parser/kramdown/codeblock' + require 'kramdown/parser/kramdown/horizontal_rule' + require 'kramdown/parser/kramdown/list' + require 'kramdown/parser/kramdown/link' + require 'kramdown/parser/kramdown/extensions' + require 'kramdown/parser/kramdown/footnote' + require 'kramdown/parser/kramdown/html' + require 'kramdown/parser/kramdown/escaped_chars' + require 'kramdown/parser/kramdown/html_entity' + require 'kramdown/parser/kramdown/line_break' + require 'kramdown/parser/kramdown/typographic_symbol' + require 'kramdown/parser/kramdown/autolink' + require 'kramdown/parser/kramdown/codespan' + require 'kramdown/parser/kramdown/emphasis' + require 'kramdown/parser/kramdown/smart_quotes' + require 'kramdown/parser/kramdown/math' + require 'kramdown/parser/kramdown/abbreviation' + + end + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/abbreviation.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/abbreviation.rb new file mode 100644 index 0000000..dbde8d2 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/abbreviation.rb @@ -0,0 +1,80 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + ABBREV_DEFINITION_START = /^#{OPT_SPACE}\*\[(.+?)\]:(.*?)\n/ + + # Parse the link definition at the current location. + def parse_abbrev_definition + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + abbrev_id, abbrev_text = @src[1], @src[2] + abbrev_text.strip! + if @root.options[:abbrev_defs][abbrev_id] + warning("Duplicate abbreviation ID '#{abbrev_id}' on line #{start_line_number} " \ + "- overwriting") + end + @tree.children << new_block_el(:eob, :abbrev_def) + @root.options[:abbrev_defs][abbrev_id] = abbrev_text + @root.options[:abbrev_attr][abbrev_id] = @tree.children.last + true + end + define_parser(:abbrev_definition, ABBREV_DEFINITION_START) + + # Correct abbreviation attributes. + def correct_abbreviations_attributes + @root.options[:abbrev_attr].keys.each do |k| + @root.options[:abbrev_attr][k] = @root.options[:abbrev_attr][k].attr + end + end + + # Replace the abbreviation text with elements. + def replace_abbreviations(el, regexps = nil) + return if @root.options[:abbrev_defs].empty? + unless regexps + sorted_abbrevs = @root.options[:abbrev_defs].keys.sort {|a, b| b.length <=> a.length } + regexps = [Regexp.union(*sorted_abbrevs.map do |k| + /#{Regexp.escape(k).gsub(/\\\s/, "[\\s\\p{Z}]+").force_encoding(Encoding::UTF_8)}/ + end)] + regexps << /(?=(?:\W|^)#{regexps.first}(?!\w))/ # regexp should only match on word boundaries + end + el.children.map! do |child| + if child.type == :text && el.options[:content_model] != :raw + if child.value.match?(regexps.first) + result = [] + strscan = Kramdown::Utils::StringScanner.new(child.value, child.options[:location]) + text_lineno = strscan.current_line_number + while (temp = strscan.scan_until(regexps.last)) + abbr_lineno = strscan.current_line_number + abbr = strscan.scan(regexps.first) # begin of line case of abbr with \W char as first one + if abbr.nil? + temp << strscan.scan(/\W|^/) + abbr = strscan.scan(regexps.first) + end + result << Element.new(:text, temp, nil, location: text_lineno) + result << Element.new(:abbreviation, abbr, nil, location: abbr_lineno) + text_lineno = strscan.current_line_number + end + result << Element.new(:text, strscan.rest, nil, location: text_lineno) + else + child + end + else + replace_abbreviations(child, regexps) + child + end + end.flatten! + end + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/autolink.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/autolink.rb new file mode 100644 index 0000000..8fa974e --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/autolink.rb @@ -0,0 +1,31 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + ACHARS = '[[:alnum:]]-_.' + AUTOLINK_START_STR = "<((mailto|https?|ftps?):.+?|[#{ACHARS}]+?@[#{ACHARS}]+?)>" + AUTOLINK_START = /#{AUTOLINK_START_STR}/u + + # Parse the autolink at the current location. + def parse_autolink + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + href = (@src[2].nil? ? "mailto:#{@src[1]}" : @src[1]) + el = Element.new(:a, nil, {'href' => href}, location: start_line_number) + add_text(@src[1].sub(/^mailto:/, ''), el) + @tree.children << el + end + define_parser(:autolink, AUTOLINK_START, '<') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blank_line.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blank_line.rb new file mode 100644 index 0000000..bb8989a --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blank_line.rb @@ -0,0 +1,30 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + BLANK_LINE = /(?>^\s*\n)+/ + + # Parse the blank line at the current postition. + def parse_blank_line + @src.pos += @src.matched_size + if (last_child = @tree.children.last) && last_child.type == :blank + last_child.value << @src.matched + else + @tree.children << new_block_el(:blank, @src.matched) + end + true + end + define_parser(:blank_line, BLANK_LINE) + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/block_boundary.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/block_boundary.rb new file mode 100644 index 0000000..daa0884 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/block_boundary.rb @@ -0,0 +1,34 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/eob' + +module Kramdown + module Parser + class Kramdown + + BLOCK_BOUNDARY = /#{BLANK_LINE}|#{EOB_MARKER}|#{IAL_BLOCK_START}|\Z/ + + # Return +true+ if we are after a block boundary. + def after_block_boundary? + last_child = @tree.children.last + !last_child || last_child.type == :blank || + (last_child.type == :eob && last_child.value.nil?) || @block_ial + end + + # Return +true+ if we are before a block boundary. + def before_block_boundary? + @src.check(self.class::BLOCK_BOUNDARY) + end + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blockquote.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blockquote.rb new file mode 100644 index 0000000..8934c5a --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blockquote.rb @@ -0,0 +1,38 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/eob' + +module Kramdown + module Parser + class Kramdown + + BLOCKQUOTE_START = /^#{OPT_SPACE}> ?/ + + # Parse the blockquote at the current location. + def parse_blockquote + start_line_number = @src.current_line_number + result = @src.scan(PARAGRAPH_MATCH) + until @src.match?(self.class::LAZY_END) + result << @src.scan(PARAGRAPH_MATCH) + end + result.gsub!(BLOCKQUOTE_START, '') + + el = new_block_el(:blockquote, nil, nil, location: start_line_number) + @tree.children << el + parse_blocks(el, result) + true + end + define_parser(:blockquote, BLOCKQUOTE_START) + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codeblock.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codeblock.rb new file mode 100644 index 0000000..b2b76d9 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codeblock.rb @@ -0,0 +1,57 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/eob' +require 'kramdown/parser/kramdown/paragraph' + +module Kramdown + module Parser + class Kramdown + + CODEBLOCK_START = INDENT + CODEBLOCK_MATCH = /(?:#{BLANK_LINE}?(?:#{INDENT}[ \t]*\S.*\n)+(?:(?!#{IAL_BLOCK_START}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}|^#{OPT_SPACE}#{LAZY_END_HTML_START})^[ \t]*\S.*\n)*)*/ + + # Parse the indented codeblock at the current location. + def parse_codeblock + start_line_number = @src.current_line_number + data = @src.scan(self.class::CODEBLOCK_MATCH) + data.gsub!(/\n( {0,3}\S)/, ' \\1') + data.gsub!(INDENT, '') + @tree.children << new_block_el(:codeblock, data, nil, location: start_line_number) + true + end + define_parser(:codeblock, CODEBLOCK_START) + + FENCED_CODEBLOCK_START = /^~{3,}/ + FENCED_CODEBLOCK_MATCH = /^((~){3,})\s*?((\S+?)(?:\?\S*)?)?\s*?\n(.*?)^\1\2*\s*?\n/m + + # Parse the fenced codeblock at the current location. + def parse_codeblock_fenced + if @src.check(self.class::FENCED_CODEBLOCK_MATCH) + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + el = new_block_el(:codeblock, @src[5], nil, location: start_line_number, fenced: true) + lang = @src[3].to_s.strip + unless lang.empty? + el.options[:lang] = lang + el.attr['class'] = "language-#{@src[4]}" + end + @tree.children << el + true + else + false + end + end + define_parser(:codeblock_fenced, FENCED_CODEBLOCK_START) + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codespan.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codespan.rb new file mode 100644 index 0000000..450d1ef --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codespan.rb @@ -0,0 +1,58 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + CODESPAN_DELIMITER = /`+/ + + # Parse the codespan at the current scanner location. + def parse_codespan + start_line_number = @src.current_line_number + result = @src.scan(CODESPAN_DELIMITER) + simple = (result.length == 1) + saved_pos = @src.save_pos + + if simple && @src.pre_match =~ /\s\Z|\A\Z/ && @src.match?(/\s/) + add_text(result) + return + end + + # assign static regex to avoid allocating the same on every instance + # where +result+ equals a single-backtick. Interpolate otherwise. + if result == '`' + scan_pattern = /`/ + str_sub_pattern = /`\Z/ + else + scan_pattern = /#{result}/ + str_sub_pattern = /#{result}\Z/ + end + + if (text = @src.scan_until(scan_pattern)) + text.sub!(str_sub_pattern, '') + unless simple + text = text[1..-1] if text[0..0] == ' ' + text = text[0..-2] if text[-1..-1] == ' ' + end + @tree.children << Element.new(:codespan, text, nil, { + codespan_delimiter: result, + location: start_line_number, + }) + + else + @src.revert_pos(saved_pos) + add_text(result) + end + end + define_parser(:codespan, CODESPAN_DELIMITER, '`') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/emphasis.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/emphasis.rb new file mode 100644 index 0000000..bedeaa0 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/emphasis.rb @@ -0,0 +1,66 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + EMPHASIS_START = /(?:\*\*?|__?)/ + + # Parse the emphasis at the current location. + def parse_emphasis + start_line_number = @src.current_line_number + saved_pos = @src.save_pos + + result = @src.scan(EMPHASIS_START) + element = (result.length == 2 ? :strong : :em) + type = result[0..0] + + if (type == '_' && @src.pre_match =~ /[[:alpha:]]-?[[:alpha:]]*_*\z/) || @src.check(/\s/) || + @tree.type == element || @stack.any? {|el, _| el.type == element } + add_text(result) + return + end + + warnings_pos = @warnings.size + sub_parse = lambda do |delim, elem| + el = Element.new(elem, nil, nil, location: start_line_number) + stop_re = /#{Regexp.escape(delim)}/ + found = parse_spans(el, stop_re) do + (@src.pre_match[-1, 1] !~ /\s/) && + (elem != :em || !@src.match?(/#{Regexp.escape(delim * 2)}(?!#{Regexp.escape(delim)})/)) && + (type != '_' || !@src.match?(/#{Regexp.escape(delim)}[[:alnum:]]/)) && !el.children.empty? + end + [found, el, stop_re] + end + + found, el, stop_re = sub_parse.call(result, element) + if !found && element == :strong && @tree.type != :em + @src.revert_pos(saved_pos) + @src.pos += 1 + found, el, stop_re = sub_parse.call(type, :em) + end + if found + # Useful for implementing underlines. + el.options[:char] = type + + @src.scan(stop_re) + @tree.children << el + else + @warnings.slice!(0...warnings_pos) + @src.revert_pos(saved_pos) + @src.pos += result.length + add_text(result) + end + end + define_parser(:emphasis, EMPHASIS_START, '\*|_') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/eob.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/eob.rb new file mode 100644 index 0000000..f151a9a --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/eob.rb @@ -0,0 +1,26 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + EOB_MARKER = /^\^\s*?\n/ + + # Parse the EOB marker at the current location. + def parse_eob_marker + @src.pos += @src.matched_size + @tree.children << new_block_el(:eob) + true + end + define_parser(:eob_marker, EOB_MARKER) + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/escaped_chars.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/escaped_chars.rb new file mode 100644 index 0000000..d63ada9 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/escaped_chars.rb @@ -0,0 +1,25 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + ESCAPED_CHARS = /\\([\\.*_+`<>()\[\]{}#!:|"'$=-])/ + + # Parse the backslash-escaped character at the current location. + def parse_escaped_chars + @src.pos += @src.matched_size + add_text(@src[1]) + end + define_parser(:escaped_chars, ESCAPED_CHARS, '\\\\') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/extensions.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/extensions.rb new file mode 100644 index 0000000..3d29115 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/extensions.rb @@ -0,0 +1,214 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + IAL_CLASS_ATTR = 'class' + + # Parse the string +str+ and extract all attributes and add all found attributes to the hash + # +opts+. + def parse_attribute_list(str, opts) + return if str.strip.empty? || str.strip == ':' + attrs = str.scan(ALD_TYPE_ANY) + attrs.each do |key, sep, val, ref, id_and_or_class, _, _| + if ref + (opts[:refs] ||= []) << ref + elsif id_and_or_class + id_and_or_class.scan(ALD_TYPE_ID_OR_CLASS).each do |id_attr, class_attr| + if class_attr + opts[IAL_CLASS_ATTR] = "#{opts[IAL_CLASS_ATTR]} #{class_attr}".lstrip + else + opts['id'] = id_attr + end + end + else + val.gsub!(/\\(\}|#{sep})/, "\\1") + opts[key] = val + end + end + warning("No or invalid attributes found in IAL/ALD content: #{str}") if attrs.empty? + end + + # Update the +ial+ with the information from the inline attribute list +opts+. + def update_ial_with_ial(ial, opts) + (ial[:refs] ||= []).concat(opts[:refs]) if opts.key?(:refs) + opts.each do |k, v| + if k == IAL_CLASS_ATTR + ial[k] = "#{ial[k]} #{v}".lstrip + elsif k.kind_of?(String) + ial[k] = v + end + end + end + + # Parse the generic extension at the current point. The parameter +type+ can either be :block + # or :span depending whether we parse a block or span extension tag. + def parse_extension_start_tag(type) + saved_pos = @src.save_pos + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + + error_block = lambda do |msg| + warning(msg) + @src.revert_pos(saved_pos) + add_text(@src.getch) if type == :span + false + end + + if @src[4] || @src.matched == '{:/}' + name = (@src[4] ? "for '#{@src[4]}' " : '') + return error_block.call("Invalid extension stop tag #{name} found on line " \ + "#{start_line_number} - ignoring it") + end + + ext = @src[1] + opts = {} + body = nil + parse_attribute_list(@src[2] || '', opts) + + unless @src[3] + stop_re = (type == :block ? /#{EXT_BLOCK_STOP_STR % ext}/ : /#{EXT_STOP_STR % ext}/) + if (result = @src.scan_until(stop_re)) + body = result.sub!(stop_re, '') + body.chomp! if type == :block + else + return error_block.call("No stop tag for extension '#{ext}' found on line " \ + "#{start_line_number} - ignoring it") + end + end + + if handle_extension(ext, opts, body, type, start_line_number) + true + else + error_block.call("Invalid extension with name '#{ext}' specified on line " \ + "#{start_line_number} - ignoring it") + end + end + + def handle_extension(name, opts, body, type, line_no = nil) + case name + when 'comment' + if body.kind_of?(String) + @tree.children << Element.new(:comment, body, nil, category: type, location: line_no) + end + true + when 'nomarkdown' + if body.kind_of?(String) + @tree.children << Element.new(:raw, body, nil, category: type, + location: line_no, type: opts['type'].to_s.split(/\s+/)) + end + true + when 'options' + opts.select do |k, v| + k = k.to_sym + if Kramdown::Options.defined?(k) + if @options[:forbidden_inline_options].include?(k) || + k == :forbidden_inline_options + warning("Option #{k} may not be set inline") + next false + end + + begin + val = Kramdown::Options.parse(k, v) + @options[k] = val + (@root.options[:options] ||= {})[k] = val + rescue StandardError + end + false + else + true + end + end.each do |k, _v| + warning("Unknown kramdown option '#{k}'") + end + @tree.children << new_block_el(:eob, :extension) if type == :block + true + else + false + end + end + + ALD_ID_CHARS = /[\w-]/ + ALD_ANY_CHARS = /\\\}|[^}]/ + ALD_ID_NAME = /\w#{ALD_ID_CHARS}*/ + ALD_CLASS_NAME = /[^\s.#]+/ + ALD_TYPE_KEY_VALUE_PAIR = /(#{ALD_ID_NAME})=("|')((?:\\\}|\\\2|[^}\2])*?)\2/ + ALD_TYPE_CLASS_NAME = /\.(#{ALD_CLASS_NAME})/ + ALD_TYPE_ID_NAME = /#([A-Za-z][\w:-]*)/ + ALD_TYPE_ID_OR_CLASS = /#{ALD_TYPE_ID_NAME}|#{ALD_TYPE_CLASS_NAME}/ + ALD_TYPE_ID_OR_CLASS_MULTI = /((?:#{ALD_TYPE_ID_NAME}|#{ALD_TYPE_CLASS_NAME})+)/ + ALD_TYPE_REF = /(#{ALD_ID_NAME})/ + ALD_TYPE_ANY = /(?:\A|\s)(?:#{ALD_TYPE_KEY_VALUE_PAIR}|#{ALD_TYPE_REF}|#{ALD_TYPE_ID_OR_CLASS_MULTI})(?=\s|\Z)/ + ALD_START = /^#{OPT_SPACE}\{:(#{ALD_ID_NAME}):(#{ALD_ANY_CHARS}+)\}\s*?\n/ + + EXT_STOP_STR = "\\{:/(%s)?\\}" + EXT_START_STR = "\\{::(\\w+)(?:\\s(#{ALD_ANY_CHARS}*?)|)(\\/)?\\}" + EXT_BLOCK_START = /^#{OPT_SPACE}(?:#{EXT_START_STR}|#{EXT_STOP_STR % ALD_ID_NAME})\s*?\n/ + EXT_BLOCK_STOP_STR = "^#{OPT_SPACE}#{EXT_STOP_STR}\s*?\n" + + IAL_BLOCK = /\{:(?!:|\/)(#{ALD_ANY_CHARS}+)\}\s*?\n/ + IAL_BLOCK_START = /^#{OPT_SPACE}#{IAL_BLOCK}/ + + BLOCK_EXTENSIONS_START = /^#{OPT_SPACE}\{:/ + + # Parse one of the block extensions (ALD, block IAL or generic extension) at the current + # location. + def parse_block_extensions + if @src.scan(ALD_START) + parse_attribute_list(@src[2], @alds[@src[1]] ||= {}) + @tree.children << new_block_el(:eob, :ald) + true + elsif @src.check(EXT_BLOCK_START) + parse_extension_start_tag(:block) + elsif @src.scan(IAL_BLOCK_START) + if (last_child = @tree.children.last) && last_child.type != :blank && + (last_child.type != :eob || + [:link_def, :abbrev_def, :footnote_def].include?(last_child.value)) + parse_attribute_list(@src[1], last_child.options[:ial] ||= {}) + @tree.children << new_block_el(:eob, :ial) unless @src.check(IAL_BLOCK_START) + else + parse_attribute_list(@src[1], @block_ial ||= {}) + end + true + else + false + end + end + define_parser(:block_extensions, BLOCK_EXTENSIONS_START) + + EXT_SPAN_START = /#{EXT_START_STR}|#{EXT_STOP_STR % ALD_ID_NAME}/ + IAL_SPAN_START = /\{:(#{ALD_ANY_CHARS}+)\}/ + SPAN_EXTENSIONS_START = /\{:/ + + # Parse the extension span at the current location. + def parse_span_extensions + if @src.check(EXT_SPAN_START) + parse_extension_start_tag(:span) + elsif @src.check(IAL_SPAN_START) + if (last_child = @tree.children.last) && last_child.type != :text + @src.pos += @src.matched_size + attr = {} + parse_attribute_list(@src[1], attr) + update_ial_with_ial(last_child.options[:ial] ||= {}, attr) + update_attr_with_ial(last_child.attr, attr) + else + warning("Found span IAL after text - ignoring it") + add_text(@src.getch) + end + else + add_text(@src.getch) + end + end + define_parser(:span_extensions, SPAN_EXTENSIONS_START, '\{:') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/footnote.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/footnote.rb new file mode 100644 index 0000000..b45fc12 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/footnote.rb @@ -0,0 +1,64 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/codeblock' + +module Kramdown + module Parser + class Kramdown + + FOOTNOTE_DEFINITION_START = /^#{OPT_SPACE}\[\^(#{ALD_ID_NAME})\]:\s*?(.*?\n#{CODEBLOCK_MATCH})/ + + # Parse the foot note definition at the current location. + def parse_footnote_definition + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + + el = Element.new(:footnote_def, nil, nil, location: start_line_number) + parse_blocks(el, @src[2].gsub(INDENT, '')) + if @footnotes[@src[1]] + warning("Duplicate footnote name '#{@src[1]}' on line #{start_line_number} - overwriting") + end + @tree.children << new_block_el(:eob, :footnote_def) + (@footnotes[@src[1]] = {})[:content] = el + @footnotes[@src[1]][:eob] = @tree.children.last + true + end + define_parser(:footnote_definition, FOOTNOTE_DEFINITION_START) + + FOOTNOTE_MARKER_START = /\[\^(#{ALD_ID_NAME})\]/ + + # Parse the footnote marker at the current location. + def parse_footnote_marker + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + fn_def = @footnotes[@src[1]] + if fn_def + if fn_def[:eob] + update_attr_with_ial(fn_def[:eob].attr, fn_def[:eob].options[:ial] || {}) + fn_def[:attr] = fn_def[:eob].attr + fn_def[:options] = fn_def[:eob].options + fn_def.delete(:eob) + end + fn_def[:marker] ||= [] + fn_def[:marker].push(Element.new(:footnote, fn_def[:content], fn_def[:attr], + fn_def[:options].merge(name: @src[1], location: start_line_number))) + @tree.children << fn_def[:marker].last + else + warning("Footnote definition for '#{@src[1]}' not found on line #{start_line_number}") + add_text(@src.matched) + end + end + define_parser(:footnote_marker, FOOTNOTE_MARKER_START, '\[') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/header.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/header.rb new file mode 100644 index 0000000..d490a46 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/header.rb @@ -0,0 +1,70 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/block_boundary' +require 'rexml/xmltokens' + +module Kramdown + module Parser + class Kramdown + + SETEXT_HEADER_START = /^#{OPT_SPACE}(?<contents>[^ \t].*)\n(?<level>[-=])[-=]*[ \t\r\f\v]*\n/ + + # Parse the Setext header at the current location. + def parse_setext_header + return false unless after_block_boundary? + text, id = parse_header_contents + return false if text.empty? + add_header(@src["level"] == '-' ? 2 : 1, text, id) + true + end + define_parser(:setext_header, SETEXT_HEADER_START) + + ATX_HEADER_START = /^(?<level>\#{1,6})[\t ]*(?<contents>[^ \t].*)\n/ + + # Parse the Atx header at the current location. + def parse_atx_header + return false unless after_block_boundary? + text, id = parse_header_contents + text.sub!(/(?<!\\)#+\z/, '') && text.rstrip! + return false if text.empty? + add_header(@src["level"].length, text, id) + true + end + define_parser(:atx_header, ATX_HEADER_START) + + protected + + HEADER_ID = /[\t ]{#(?<id>#{REXML::XMLTokens::NAME_START_CHAR}#{REXML::XMLTokens::NAME_CHAR}*)}\z/ + + # Returns header text and optional ID. + def parse_header_contents + text = @src["contents"] + text.rstrip! + id_match = HEADER_ID.match(text) + if id_match + id = id_match["id"] + text = text[0...-id_match[0].length] + text.rstrip! + end + [text, id] + end + + def add_header(level, text, id) + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + el = new_block_el(:header, nil, nil, level: level, raw_text: text, location: start_line_number) + add_text(text, el) + el.attr['id'] = id if id + @tree.children << el + end + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/horizontal_rule.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/horizontal_rule.rb new file mode 100644 index 0000000..73a936d --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/horizontal_rule.rb @@ -0,0 +1,27 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + HR_START = /^#{OPT_SPACE}(\*|-|_)[ \t]*\1[ \t]*\1(\1|[ \t])*\n/ + + # Parse the horizontal rule at the current location. + def parse_horizontal_rule + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + @tree.children << new_block_el(:hr, nil, nil, location: start_line_number) + true + end + define_parser(:horizontal_rule, HR_START) + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html.rb new file mode 100644 index 0000000..c0fcd1a --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html.rb @@ -0,0 +1,165 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/html' + +module Kramdown + module Parser + class Kramdown + + include Kramdown::Parser::Html::Parser + include Kramdown::Utils::Html + + # Mapping of markdown attribute value to content model. I.e. :raw when "0", :default when "1" + # (use default content model for the HTML element), :span when "span", :block when block and + # for everything else +nil+ is returned. + HTML_MARKDOWN_ATTR_MAP = {"0" => :raw, "1" => :default, "span" => :span, "block" => :block} + + TRAILING_WHITESPACE = /[ \t]*\n/ + + def handle_kramdown_html_tag(el, closed, handle_body) + if @block_ial + el.options[:ial] = @block_ial + @block_ial = nil + end + + content_model = if @tree.type != :html_element || @tree.options[:content_model] != :raw + (@options[:parse_block_html] ? HTML_CONTENT_MODEL[el.value] : :raw) + else + :raw + end + if (val = HTML_MARKDOWN_ATTR_MAP[el.attr.delete('markdown')]) + content_model = (val == :default ? HTML_CONTENT_MODEL[el.value] : val) + end + + @src.scan(TRAILING_WHITESPACE) if content_model == :block + el.options[:content_model] = content_model + el.options[:is_closed] = closed + + if !closed && handle_body + case content_model + when :block + unless parse_blocks(el) + warning("Found no end tag for '#{el.value}' (line #{el.options[:location]}) - auto-closing it") + end + when :span + curpos = @src.pos + if @src.scan_until(/(?=<\/#{el.value}\s*>)/mi) + add_text(extract_string(curpos...@src.pos, @src), el) + @src.scan(HTML_TAG_CLOSE_RE) + else + add_text(@src.rest, el) + @src.terminate + warning("Found no end tag for '#{el.value}' (line #{el.options[:location]}) - auto-closing it") + end + else + parse_raw_html(el) {|iel, ic, ih| handle_kramdown_html_tag(iel, ic, ih) } + end + unless @tree.type == :html_element && @tree.options[:content_model] == :raw + @src.scan(TRAILING_WHITESPACE) + end + end + end + + HTML_BLOCK_START = /^#{OPT_SPACE}<(#{REXML::Parsers::BaseParser::UNAME_STR}|!--|\/)/ + + # Parse the HTML at the current position as block-level HTML. + def parse_block_html + line = @src.current_line_number + if (result = @src.scan(HTML_COMMENT_RE)) + @tree.children << Element.new(:xml_comment, result, nil, category: :block, location: line) + @src.scan(TRAILING_WHITESPACE) + true + elsif @src.check(/^#{OPT_SPACE}#{HTML_TAG_RE}/o) && !HTML_SPAN_ELEMENTS.include?(@src[1].downcase) + @src.pos += @src.matched_size + handle_html_start_tag(line) {|iel, ic, ih| handle_kramdown_html_tag(iel, ic, ih) } + Kramdown::Parser::Html::ElementConverter.convert(@root, @tree.children.last) if @options[:html_to_native] + true + elsif @src.check(/^#{OPT_SPACE}#{HTML_TAG_CLOSE_RE}/o) && !HTML_SPAN_ELEMENTS.include?(@src[1].downcase) + name = @src[1].downcase + + if @tree.type == :html_element && @tree.value == name + @src.pos += @src.matched_size + throw :stop_block_parsing, :found + else + false + end + else + false + end + end + define_parser(:block_html, HTML_BLOCK_START) + + HTML_SPAN_START = /<(#{REXML::Parsers::BaseParser::UNAME_STR}|!--|\/|!\[CDATA\[)/ + + # Parse the HTML at the current position as span-level HTML. + def parse_span_html + line = @src.current_line_number + if (result = @src.scan(HTML_COMMENT_RE)) + @tree.children << Element.new(:xml_comment, result, nil, category: :span, location: line) + elsif @src.scan(HTML_CDATA_RE) + add_text(escape_html(@src[1])) + elsif (result = @src.scan(HTML_TAG_CLOSE_RE)) + warning("Found invalidly used HTML closing tag for '#{@src[1]}' on line #{line}") + add_text(result) + elsif (result = @src.scan(HTML_TAG_RE)) + tag_name = @src[1] + tag_name.downcase! if HTML_ELEMENT[tag_name.downcase] + if HTML_BLOCK_ELEMENTS.include?(tag_name) + warning("Found block HTML tag '#{tag_name}' in span-level text on line #{line}") + add_text(result) + return + end + + attrs = parse_html_attributes(@src[2], line, HTML_ELEMENT[tag_name]) + attrs.each_value {|value| value.gsub!(/\n+/, ' ') unless value.empty? } + + do_parsing = if HTML_CONTENT_MODEL[tag_name] == :raw || @tree.options[:content_model] == :raw + false + else + @options[:parse_span_html] + end + if (val = HTML_MARKDOWN_ATTR_MAP[attrs.delete('markdown')]) + case val + when :block + warning("Cannot use block-level parsing in span-level HTML tag (line #{line}) " \ + "- using default mode") + when :span + do_parsing = true + when :default + do_parsing = HTML_CONTENT_MODEL[tag_name] != :raw + when :raw + do_parsing = false + end + end + + el = Element.new(:html_element, tag_name, attrs, category: :span, location: line, + content_model: (do_parsing ? :span : :raw), is_closed: !@src[4].nil?) + @tree.children << el + stop_re = /<\/#{Regexp.escape(tag_name)}\s*>/ + stop_re = Regexp.new(stop_re.source, Regexp::IGNORECASE) if HTML_ELEMENT[tag_name] + if !@src[4] && !HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) + if parse_spans(el, stop_re, (do_parsing ? nil : [:span_html])) + @src.scan(stop_re) + else + warning("Found no end tag for '#{el.value}' (line #{line}) - auto-closing it") + add_text(@src.rest, el) + @src.terminate + end + end + Kramdown::Parser::Html::ElementConverter.convert(@root, el) if @options[:html_to_native] + else + add_text(@src.getch) + end + end + define_parser(:span_html, HTML_SPAN_START, '<') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html_entity.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html_entity.rb new file mode 100644 index 0000000..9852df7 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html_entity.rb @@ -0,0 +1,34 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/html' + +module Kramdown + module Parser + class Kramdown + + # Parse the HTML entity at the current location. + def parse_html_entity + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + begin + value = ::Kramdown::Utils::Entities.entity(@src[1] || @src[2]&.to_i || @src[3].hex) + @tree.children << Element.new(:entity, value, + nil, original: @src.matched, location: start_line_number) + rescue ::Kramdown::Error + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('amp'), + nil, location: start_line_number) + add_text(@src.matched[1..-1]) + end + end + define_parser(:html_entity, Kramdown::Parser::Html::Constants::HTML_ENTITY_RE, '&') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/line_break.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/line_break.rb new file mode 100644 index 0000000..5f85427 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/line_break.rb @@ -0,0 +1,25 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + LINE_BREAK = /( |\\\\)(?=\n)/ + + # Parse the line break at the current location. + def parse_line_break + @tree.children << Element.new(:br, nil, nil, location: @src.current_line_number) + @src.pos += @src.matched_size + end + define_parser(:line_break, LINE_BREAK, '( |\\\\)(?=\n)') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/link.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/link.rb new file mode 100644 index 0000000..e4c0935 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/link.rb @@ -0,0 +1,149 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/escaped_chars' + +module Kramdown + module Parser + class Kramdown + + # Normalize the link identifier. + def normalize_link_id(id) + id.gsub(/\s+/, ' ').downcase + end + + LINK_DEFINITION_START = /^#{OPT_SPACE}\[([^\n\]]+)\]:[ \t]*(?:<(.*?)>|([^\n]*?\S[^\n]*?))(?:(?:[ \t]*?\n|[ \t]+?)[ \t]*?(["'])(.+?)\4)?[ \t]*?\n/ + + # Parse the link definition at the current location. + def parse_link_definition + return false if @src[3].to_s.match?(/[ \t]+["']/) + @src.pos += @src.matched_size + link_id, link_url, link_title = normalize_link_id(@src[1]), @src[2] || @src[3], @src[5] + if @link_defs[link_id] + warning("Duplicate link ID '#{link_id}' on line #{@src.current_line_number} - overwriting") + end + @tree.children << new_block_el(:eob, :link_def) + @link_defs[link_id] = [link_url, link_title, @tree.children.last] + true + end + define_parser(:link_definition, LINK_DEFINITION_START) + + # This helper methods adds the approriate attributes to the element +el+ of type +a+ or +img+ + # and the element itself to the @tree. + def add_link(el, href, title, alt_text = nil, ial = nil) + el.options[:ial] = ial + update_attr_with_ial(el.attr, ial) if ial + if el.type == :a + el.attr['href'] = href + else + el.attr['src'] = href + el.attr['alt'] = alt_text + el.children.clear + end + el.attr['title'] = title if title + @tree.children << el + end + + LINK_BRACKET_STOP_RE = /(\])|!?\[/ + LINK_PAREN_STOP_RE = /(\()|(\))|\s(?=['"])/ + LINK_INLINE_ID_RE = /\s*?\[([^\]]+)?\]/ + LINK_INLINE_TITLE_RE = /\s*?(["'])(.+?)\1\s*?\)/m + LINK_START = /!?\[(?=[^^])/ + + # Parse the link at the current scanner position. This method is used to parse normal links as + # well as image links. + def parse_link + start_line_number = @src.current_line_number + result = @src.scan(LINK_START) + cur_pos = @src.pos + saved_pos = @src.save_pos + + link_type = (result.match?(/^!/) ? :img : :a) + + # no nested links allowed + if link_type == :a && (@tree.type == :img || @tree.type == :a || + @stack.any? {|t, _| t && (t.type == :img || t.type == :a) }) + add_text(result) + return + end + el = Element.new(link_type, nil, nil, location: start_line_number) + + count = 1 + found = parse_spans(el, LINK_BRACKET_STOP_RE) do + count += (@src[1] ? -1 : 1) + count - el.children.count {|c| c.type == :img } == 0 + end + unless found + @src.revert_pos(saved_pos) + add_text(result) + return + end + alt_text = extract_string(cur_pos...@src.pos, @src).gsub(ESCAPED_CHARS, '\1') + @src.scan(LINK_BRACKET_STOP_RE) + + # reference style link or no link url + if @src.scan(LINK_INLINE_ID_RE) || !@src.check(/\(/) + emit_warning = !@src[1] + link_id = normalize_link_id(@src[1] || alt_text) + if @link_defs.key?(link_id) + link_def = @link_defs[link_id] + add_link(el, link_def[0], link_def[1], alt_text, + link_def[2] && link_def[2].options[:ial]) + else + if emit_warning + warning("No link definition for link ID '#{link_id}' found on line #{start_line_number}") + end + @src.revert_pos(saved_pos) + add_text(result) + end + return + end + + # link url in parentheses + if @src.scan(/\(<(.*?)>/) + link_url = @src[1] + if @src.scan(/\)/) + add_link(el, link_url, nil, alt_text) + return + end + else + link_url = +'' + nr_of_brackets = 0 + while (temp = @src.scan_until(LINK_PAREN_STOP_RE)) + link_url << temp + if @src[2] + nr_of_brackets -= 1 + break if nr_of_brackets == 0 + elsif @src[1] + nr_of_brackets += 1 + else + break + end + end + link_url = link_url[1..-2] + link_url.strip! + + if nr_of_brackets == 0 + add_link(el, link_url, nil, alt_text) + return + end + end + + if @src.scan(LINK_INLINE_TITLE_RE) + add_link(el, link_url, @src[2], alt_text) + else + @src.revert_pos(saved_pos) + add_text(result) + end + end + define_parser(:link, LINK_START, '!?\[') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/list.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/list.rb new file mode 100644 index 0000000..4cf9d3f --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/list.rb @@ -0,0 +1,286 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/eob' +require 'kramdown/parser/kramdown/horizontal_rule' +require 'kramdown/parser/kramdown/extensions' + +module Kramdown + module Parser + class Kramdown + + LIST_ITEM_IAL = /^\s*(?:\{:(?!(?:#{ALD_ID_NAME})?:|\/)(#{ALD_ANY_CHARS}+)\})\s*/ + LIST_ITEM_IAL_CHECK = /^#{LIST_ITEM_IAL}?\s*\n/ + + PARSE_FIRST_LIST_LINE_REGEXP_CACHE = Hash.new do |h, indentation| + indent_re = /^ {#{indentation}}/ + content_re = /^(?:(?:\t| {4}){#{indentation / 4}} {#{indentation % 4}}|(?:\t| {4}){#{indentation / 4 + 1}}).*\S.*\n/ + lazy_re = /(?!^ {0,#{[indentation, 3].min}}(?:#{IAL_BLOCK}|#{LAZY_END_HTML_STOP}|#{LAZY_END_HTML_START})).*\S.*\n/ + + h[indentation] = [content_re, lazy_re, indent_re] + end + + # Used for parsing the first line of a list item or a definition, i.e. the line with list item + # marker or the definition marker. + def parse_first_list_line(indentation, content) + if content.match?(self.class::LIST_ITEM_IAL_CHECK) + indentation = 4 + else + while content.match?(/^ *\t/) + temp = content.scan(/^ */).first.length + indentation + content.sub!(/^( *)(\t+)/) { $1 << " " * (4 - (temp % 4) + ($2.length - 1) * 4) } + end + indentation += content[/^ */].length + end + content.sub!(/^\s*/, '') + + [content, indentation, *PARSE_FIRST_LIST_LINE_REGEXP_CACHE[indentation]] + end + + PATTERN_TAIL = /[\t| ].*?\n/ + + LIST_START_UL = /^(#{OPT_SPACE}[+*-])(#{PATTERN_TAIL})/ + LIST_START_OL = /^(#{OPT_SPACE}\d+\.)(#{PATTERN_TAIL})/ + LIST_START = /#{LIST_START_UL}|#{LIST_START_OL}/ + + # Parse the ordered or unordered list at the current location. + def parse_list + start_line_number = @src.current_line_number + type, list_start_re = (@src.check(LIST_START_UL) ? [:ul, LIST_START_UL] : [:ol, LIST_START_OL]) + list = new_block_el(type, nil, nil, location: start_line_number) + + item = nil + content_re, lazy_re, indent_re = nil + eob_found = false + nested_list_found = false + last_is_blank = false + until @src.eos? + start_line_number = @src.current_line_number + if last_is_blank && @src.check(HR_START) + break + elsif @src.scan(EOB_MARKER) + eob_found = true + break + elsif @src.scan(list_start_re) + list.options[:first_list_marker] ||= @src[1].strip + item = Element.new(:li, nil, nil, location: start_line_number) + item.value, indentation, content_re, lazy_re, indent_re = + parse_first_list_line(@src[1].length, @src[2]) + list.children << item + + item.value.sub!(self.class::LIST_ITEM_IAL) do + parse_attribute_list($1, item.options[:ial] ||= {}) + '' + end + + list_start_re = fetch_pattern(type, indentation) + nested_list_found = (item.value =~ LIST_START) + last_is_blank = false + item.value = [item.value] + elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re))) + result.sub!(/^(\t+)/) { " " * 4 * $1.length } + indentation_found = result.sub!(indent_re, '') + if !nested_list_found && indentation_found && result =~ LIST_START + item.value << +'' + nested_list_found = true + elsif nested_list_found && !indentation_found && result =~ LIST_START + result = " " * (indentation + 4) << result + end + item.value.last << result + last_is_blank = false + elsif (result = @src.scan(BLANK_LINE)) + nested_list_found = true + last_is_blank = true + item.value.last << result + else + break + end + end + + @tree.children << list + + last = nil + list.children.each do |it| + temp = Element.new(:temp, nil, nil, location: it.options[:location]) + + env = save_env + location = it.options[:location] + it.value.each do |val| + @src = ::Kramdown::Utils::StringScanner.new(val, location) + parse_blocks(temp) + location = @src.current_line_number + end + restore_env(env) + + it.children = temp.children + it.value = nil + + it_children = it.children + next if it_children.empty? + + # Handle the case where an EOB marker is inserted by a block IAL for the first paragraph + it_children.delete_at(1) if it_children.first.type == :p && + it_children.length >= 2 && it_children[1].type == :eob && it_children.first.options[:ial] + + if it_children.first.type == :p && + (it_children.length < 2 || it_children[1].type != :blank || + (it == list.children.last && it_children.length == 2 && !eob_found)) && + (list.children.last != it || list.children.size == 1 || + list.children[0..-2].any? {|cit| !cit.children.first || cit.children.first.type != :p || cit.children.first.options[:transparent] }) + it_children.first.children.first.value << "\n" if it_children.size > 1 && it_children[1].type != :blank + it_children.first.options[:transparent] = true + end + + last = (it_children.last.type == :blank ? it_children.pop : nil) + end + + @tree.children << last if !last.nil? && !eob_found + + true + end + define_parser(:list, LIST_START) + + DEFINITION_LIST_START = /^(#{OPT_SPACE}:)(#{PATTERN_TAIL})/ + + # Parse the ordered or unordered list at the current location. + def parse_definition_list + children = @tree.children + if !children.last || (children.length == 1 && children.last.type != :p) || + (children.length >= 2 && children[-1].type != :p && + (children[-1].type != :blank || children[-1].value != "\n" || children[-2].type != :p)) + return false + end + + first_as_para = false + deflist = new_block_el(:dl) + para = @tree.children.pop + if para.type == :blank + para = @tree.children.pop + first_as_para = true + end + # take location from preceding para which is the first definition term + deflist.options[:location] = para.options[:location] + para.children.first.value.split("\n").each do |term| + el = Element.new(:dt, nil, nil, location: @src.current_line_number) + term.sub!(self.class::LIST_ITEM_IAL) do + parse_attribute_list($1, el.options[:ial] ||= {}) + '' + end + el.options[:raw_text] = term + el.children << Element.new(:raw_text, term) + deflist.children << el + end + deflist.options[:ial] = para.options[:ial] + + item = nil + content_re, lazy_re, indent_re = nil + def_start_re = DEFINITION_LIST_START + last_is_blank = false + until @src.eos? + start_line_number = @src.current_line_number + if @src.scan(def_start_re) + item = Element.new(:dd, nil, nil, location: start_line_number) + item.options[:first_as_para] = first_as_para + item.value, indentation, content_re, lazy_re, indent_re = + parse_first_list_line(@src[1].length, @src[2]) + deflist.children << item + + item.value.sub!(self.class::LIST_ITEM_IAL) do |_match| + parse_attribute_list($1, item.options[:ial] ||= {}) + '' + end + + def_start_re = fetch_pattern(:dl, indentation) + first_as_para = false + last_is_blank = false + elsif @src.check(EOB_MARKER) + break + elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re))) + result.sub!(/^(\t+)/) { " " * ($1 ? 4 * $1.length : 0) } + result.sub!(indent_re, '') + item.value << result + first_as_para = false + last_is_blank = false + elsif (result = @src.scan(BLANK_LINE)) + first_as_para = true + item.value << result + last_is_blank = true + else + break + end + end + + last = nil + deflist.children.each do |it| + next if it.type == :dt + + parse_blocks(it, it.value) + it.value = nil + it_children = it.children + next if it_children.empty? + + last = (it_children.last.type == :blank ? it_children.pop : nil) + + if it_children.first && it_children.first.type == :p && !it.options.delete(:first_as_para) + it_children.first.children.first.value << "\n" if it_children.size > 1 + it_children.first.options[:transparent] = true + end + end + + children = @tree.children + if children.length >= 1 && children.last.type == :dl + children[-1].children.concat(deflist.children) + elsif children.length >= 2 && children[-1].type == :blank && + children[-2].type == :dl + children.pop + children[-1].children.concat(deflist.children) + else + children << deflist + end + + children << last if last + + true + end + define_parser(:definition_list, DEFINITION_LIST_START) + + private + + # precomputed patterns for indentations 1..4 and fallback expression + # to compute pattern when indentation is outside the 1..4 range. + def fetch_pattern(type, indentation) + case type + when :ul + case indentation + when 1 then /^( {0}[+*-])(#{PATTERN_TAIL})/o + when 2 then /^( {0,1}[+*-])(#{PATTERN_TAIL})/o + when 3 then /^( {0,2}[+*-])(#{PATTERN_TAIL})/o + else /^( {0,3}[+*-])(#{PATTERN_TAIL})/o + end + when :ol + case indentation + when 1 then /^( {0}\d+\.)(#{PATTERN_TAIL})/o + when 2 then /^( {0,1}\d+\.)(#{PATTERN_TAIL})/o + when 3 then /^( {0,2}\d+\.)(#{PATTERN_TAIL})/o + else /^( {0,3}\d+\.)(#{PATTERN_TAIL})/o + end + when :dl + case indentation + when 1 then /^( {0}:)(#{PATTERN_TAIL})/o + when 2 then /^( {0,1}:)(#{PATTERN_TAIL})/o + when 3 then /^( {0,2}:)(#{PATTERN_TAIL})/o + else /^( {0,3}:)(#{PATTERN_TAIL})/o + end + end + end + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/math.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/math.rb new file mode 100644 index 0000000..32c87bf --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/math.rb @@ -0,0 +1,53 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/block_boundary' + +module Kramdown + module Parser + class Kramdown + + BLOCK_MATH_START = /^#{OPT_SPACE}(\\)?\$\$(.*?)\$\$(\s*?\n)?/m + + # Parse the math block at the current location. + def parse_block_math + start_line_number = @src.current_line_number + if !after_block_boundary? + return false + elsif @src[1] + @src.scan(/^#{OPT_SPACE}\\/o) if @src[3] + return false + end + + saved_pos = @src.save_pos + @src.pos += @src.matched_size + data = @src[2].strip + if before_block_boundary? + @tree.children << new_block_el(:math, data, nil, category: :block, location: start_line_number) + true + else + @src.revert_pos(saved_pos) + false + end + end + define_parser(:block_math, BLOCK_MATH_START) + + INLINE_MATH_START = /\$\$(.*?)\$\$/m + + # Parse the inline math at the current location. + def parse_inline_math + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + @tree.children << Element.new(:math, @src[1].strip, nil, category: :span, location: start_line_number) + end + define_parser(:inline_math, INLINE_MATH_START, '\$') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/paragraph.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/paragraph.rb new file mode 100644 index 0000000..d89e6a2 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/paragraph.rb @@ -0,0 +1,62 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/eob' +require 'kramdown/parser/kramdown/list' +require 'kramdown/parser/kramdown/html' + +module Kramdown + module Parser + class Kramdown + + LAZY_END_HTML_SPAN_ELEMENTS = HTML_SPAN_ELEMENTS + %w[script] + LAZY_END_HTML_START = /<(?>(?!(?:#{LAZY_END_HTML_SPAN_ELEMENTS.join('|')})\b)#{REXML::Parsers::BaseParser::UNAME_STR})/ + LAZY_END_HTML_STOP = /<\/(?!(?:#{LAZY_END_HTML_SPAN_ELEMENTS.join('|')})\b)#{REXML::Parsers::BaseParser::UNAME_STR}\s*>/m + + LAZY_END = /#{BLANK_LINE}|#{IAL_BLOCK_START}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}|^#{OPT_SPACE}#{LAZY_END_HTML_START}|\Z/ + + PARAGRAPH_START = /^#{OPT_SPACE}[^ \t].*?\n/ + PARAGRAPH_MATCH = /^.*?\n/ + PARAGRAPH_END = /#{LAZY_END}|#{DEFINITION_LIST_START}/ + + # Parse the paragraph at the current location. + def parse_paragraph + pos = @src.pos + start_line_number = @src.current_line_number + result = @src.scan(PARAGRAPH_MATCH) + until @src.match?(paragraph_end) + result << @src.scan(PARAGRAPH_MATCH) + end + result.rstrip! + if (last_child = @tree.children.last) && last_child.type == :p + last_item_in_para = last_child.children.last + if last_item_in_para && last_item_in_para.type == @text_type + joiner = (extract_string((pos - 3)...pos, @src) == " \n" ? " \n" : "\n") + last_item_in_para.value << joiner << result + else + add_text(result, last_child) + end + else + @tree.children << new_block_el(:p, nil, nil, location: start_line_number) + result.lstrip! + add_text(result, @tree.children.last) + end + true + end + define_parser(:paragraph, PARAGRAPH_START) + + def paragraph_end + self.class::PARAGRAPH_END + end + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/smart_quotes.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/smart_quotes.rb new file mode 100644 index 0000000..c0a6aaa --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/smart_quotes.rb @@ -0,0 +1,174 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# +#-- +# Parts of this file are based on code from RubyPants: +# +# = RubyPants -- SmartyPants ported to Ruby +# +# Ported by Christian Neukirchen <mailto:chneukirchen@gmail.com> +# Copyright (C) 2004 Christian Neukirchen +# +# Incooporates ideas, comments and documentation by Chad Miller +# Copyright (C) 2004 Chad Miller +# +# Original SmartyPants by John Gruber +# Copyright (C) 2003 John Gruber +# +# +# = RubyPants -- SmartyPants ported to Ruby +# +# +# [snip] +# +# == Authors +# +# John Gruber did all of the hard work of writing this software in +# Perl for Movable Type and almost all of this useful documentation. +# Chad Miller ported it to Python to use with Pyblosxom. +# +# Christian Neukirchen provided the Ruby port, as a general-purpose +# library that follows the *Cloth API. +# +# +# == Copyright and License +# +# === SmartyPants license: +# +# Copyright (c) 2003 John Gruber +# (http://daringfireball.net) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# * Neither the name "SmartyPants" nor the names of its contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# This software is provided by the copyright holders and contributors +# "as is" and any express or implied warranties, including, but not +# limited to, the implied warranties of merchantability and fitness +# for a particular purpose are disclaimed. In no event shall the +# copyright owner or contributors be liable for any direct, indirect, +# incidental, special, exemplary, or consequential damages (including, +# but not limited to, procurement of substitute goods or services; +# loss of use, data, or profits; or business interruption) however +# caused and on any theory of liability, whether in contract, strict +# liability, or tort (including negligence or otherwise) arising in +# any way out of the use of this software, even if advised of the +# possibility of such damage. +# +# === RubyPants license +# +# RubyPants is a derivative work of SmartyPants and smartypants.py. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# This software is provided by the copyright holders and contributors +# "as is" and any express or implied warranties, including, but not +# limited to, the implied warranties of merchantability and fitness +# for a particular purpose are disclaimed. In no event shall the +# copyright owner or contributors be liable for any direct, indirect, +# incidental, special, exemplary, or consequential damages (including, +# but not limited to, procurement of substitute goods or services; +# loss of use, data, or profits; or business interruption) however +# caused and on any theory of liability, whether in contract, strict +# liability, or tort (including negligence or otherwise) arising in +# any way out of the use of this software, even if advised of the +# possibility of such damage. +# +# == Links +# +# John Gruber:: http://daringfireball.net +# SmartyPants:: http://daringfireball.net/projects/smartypants +# +# Chad Miller:: http://web.chad.org +# +# Christian Neukirchen:: http://kronavita.de/chris +# +#++ +# + +module Kramdown + module Parser + class Kramdown + + SQ_PUNCT = '[!"#\$\%\'()*+,\-.\/:;<=>?\@\[\\\\\]\^_`{|}~]' + SQ_CLOSE = %![^ \\\\\t\r\n\\[{(-]! + + SQ_RULES = [ + [/("|')(?=[_*]{1,2}\S)/, [:lquote1]], + [/("|')(?=#{SQ_PUNCT}(?!\.\.)\B)/, [:rquote1]], + # Special case for double sets of quotes, e.g.: + # <p>He said, "'Quoted' words in a larger quote."</p> + [/(\s?)"'(?=\w)/, [1, :ldquo, :lsquo]], + [/(\s?)'"(?=\w)/, [1, :lsquo, :ldquo]], + # Special case for decade abbreviations (the '80s): + [/(\s?)'(?=\d\ds)/, [1, :rsquo]], + + # Get most opening single/double quotes: + [/(\s)('|")(?=\w)/, [1, :lquote2]], + # Single/double closing quotes: + [/(#{SQ_CLOSE})('|")/, [1, :rquote2]], + # Special case for e.g. "<i>Custer</i>'s Last Stand." + [/("|')(?=\s|s\b|$)/, [:rquote1]], + # Any remaining single quotes should be opening ones: + [/(.?)'/m, [1, :lsquo]], + [/(.?)"/m, [1, :ldquo]], + ] # '" + + SQ_SUBSTS = { + [:rquote1, '"'] => :rdquo, + [:rquote1, "'"] => :rsquo, + [:rquote2, '"'] => :rdquo, + [:rquote2, "'"] => :rsquo, + [:lquote1, '"'] => :ldquo, + [:lquote1, "'"] => :lsquo, + [:lquote2, '"'] => :ldquo, + [:lquote2, "'"] => :lsquo, + } + SMART_QUOTES_RE = /[^\\]?["']/ + + # Parse the smart quotes at current location. + def parse_smart_quotes + start_line_number = @src.current_line_number + substs = SQ_RULES.find {|reg, _subst| @src.scan(reg) }[1] + substs.each do |subst| + if subst.kind_of?(Integer) + add_text(@src[subst]) + else + val = SQ_SUBSTS[[subst, @src[subst.to_s[-1, 1].to_i]]] || subst + @tree.children << Element.new(:smart_quote, val, nil, location: start_line_number) + end + end + end + define_parser(:smart_quotes, SMART_QUOTES_RE, '[^\\\\]?["\']') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/table.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/table.rb new file mode 100644 index 0000000..68be6b4 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/table.rb @@ -0,0 +1,171 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/block_boundary' + +module Kramdown + module Parser + class Kramdown + + TABLE_SEP_LINE = /^([+|: \t-]*?-[+|: \t-]*?)[ \t]*\n/ + TABLE_HSEP_ALIGN = /[ \t]?(:?)-+(:?)[ \t]?/ + TABLE_FSEP_LINE = /^[+|: \t=]*?=[+|: \t=]*?[ \t]*\n/ + TABLE_ROW_LINE = /^(.*?)[ \t]*\n/ + TABLE_PIPE_CHECK = /(?:\||.*?[^\\\n]\|)/ + TABLE_LINE = /#{TABLE_PIPE_CHECK}.*?\n/ + TABLE_START = /^#{OPT_SPACE}(?=\S)#{TABLE_LINE}/ + + # Parse the table at the current location. + def parse_table + return false unless after_block_boundary? + + saved_pos = @src.save_pos + orig_pos = @src.pos + table = new_block_el(:table, nil, nil, alignment: [], location: @src.current_line_number) + leading_pipe = (@src.check(TABLE_LINE) =~ /^\s*\|/) + @src.scan(TABLE_SEP_LINE) + + rows = [] + has_footer = false + columns = 0 + + add_container = lambda do |type, force| + if !has_footer || type != :tbody || force + cont = Element.new(type) + cont.children, rows = rows, [] + table.children << cont + end + end + + until @src.eos? + break unless @src.check(TABLE_LINE) + if @src.scan(TABLE_SEP_LINE) + if rows.empty? + # nothing to do, ignoring multiple consecutive separator lines + elsif table.options[:alignment].empty? && !has_footer + add_container.call(:thead, false) + table.options[:alignment] = @src[1].scan(TABLE_HSEP_ALIGN).map do |left, right| + (left.empty? && right.empty? && :default) || (right.empty? && :left) || + (left.empty? && :right) || :center + end + else # treat as normal separator line + add_container.call(:tbody, false) + end + elsif @src.scan(TABLE_FSEP_LINE) + add_container.call(:tbody, true) unless rows.empty? + has_footer = true + elsif @src.scan(TABLE_ROW_LINE) + trow = Element.new(:tr) + + # parse possible code spans on the line and correctly split the line into cells + env = save_env + cells = [] + @src[1].split(/(<code.*?>.*?<\/code>)/).each_with_index do |str, i| + if i.odd? + (cells.empty? ? cells : cells.last) << str + else + reset_env(src: Kramdown::Utils::StringScanner.new(str, @src.current_line_number)) + root = Element.new(:root) + parse_spans(root, nil, [:codespan]) + + root.children.each do |c| + if c.type == :raw_text + f, *l = c.value.split(/(?<!\\)\|/, -1).map {|t| t.gsub(/\\\|/, '|') } + (cells.empty? ? cells : cells.last) << f + cells.concat(l) + else + delim = (c.value.scan(/`+/).max || '') + '`' + tmp = +"#{delim}#{' ' if delim.size > 1}#{c.value}#{' ' if delim.size > 1}#{delim}" + (cells.empty? ? cells : cells.last) << tmp + end + end + end + end + restore_env(env) + + cells.shift if leading_pipe && cells.first.strip.empty? + cells.pop if cells.last.strip.empty? + cells.each do |cell_text| + tcell = Element.new(:td) + tcell.children << Element.new(:raw_text, cell_text.strip) + trow.children << tcell + end + columns = [columns, cells.length].max + rows << trow + else + break + end + end + + unless before_block_boundary? + @src.revert_pos(saved_pos) + return false + end + + # Parse all lines of the table with the code span parser + env = save_env + l_src = ::Kramdown::Utils::StringScanner.new(extract_string(orig_pos...(@src.pos - 1), @src), + @src.current_line_number) + reset_env(src: l_src) + root = Element.new(:root) + parse_spans(root, nil, [:codespan, :span_html]) + restore_env(env) + + # Check if each line has at least one unescaped pipe that is not inside a code span/code + # HTML element + # Note: It doesn't matter that we parse *all* span HTML elements because the row splitting + # algorithm above only takes <code> elements into account! + pipe_on_line = false + while (c = root.children.shift) + next unless (lines = c.value) + lines = lines.split("\n") + if c.type == :codespan + if lines.size > 2 || (lines.size == 2 && !pipe_on_line) + break + elsif lines.size == 2 && pipe_on_line + pipe_on_line = false + end + else + break if lines.size > 1 && !pipe_on_line && lines.first !~ /^#{TABLE_PIPE_CHECK}/o + pipe_on_line = (lines.size > 1 ? false : pipe_on_line) || (lines.last =~ /^#{TABLE_PIPE_CHECK}/o) + end + end + @src.revert_pos(saved_pos) and return false unless pipe_on_line + + add_container.call(has_footer ? :tfoot : :tbody, false) unless rows.empty? + + if table.children.none? {|el| el.type == :tbody } + warning("Found table without body on line #{table.options[:location]} - ignoring it") + @src.revert_pos(saved_pos) + return false + end + + # adjust all table rows to have equal number of columns, same for alignment defs + table.children.each do |kind| + kind.children.each do |row| + (columns - row.children.length).times do + row.children << Element.new(:td) + end + end + end + if table.options[:alignment].length > columns + table.options[:alignment] = table.options[:alignment][0...columns] + else + table.options[:alignment] += [:default] * (columns - table.options[:alignment].length) + end + + @tree.children << table + + true + end + define_parser(:table, TABLE_START) + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/typographic_symbol.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/typographic_symbol.rb new file mode 100644 index 0000000..095c8d5 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/typographic_symbol.rb @@ -0,0 +1,44 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + TYPOGRAPHIC_SYMS = [['---', :mdash], ['--', :ndash], ['...', :hellip], + ['\\<<', '<<'], ['\\>>', '>>'], + ['<< ', :laquo_space], [' >>', :raquo_space], + ['<<', :laquo], ['>>', :raquo]] + TYPOGRAPHIC_SYMS_SUBST = Hash[*TYPOGRAPHIC_SYMS.flatten] + TYPOGRAPHIC_SYMS_RE = /#{TYPOGRAPHIC_SYMS.map {|k, _v| Regexp.escape(k) }.join('|')}/ + + # Parse the typographic symbols at the current location. + def parse_typographic_syms + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + val = TYPOGRAPHIC_SYMS_SUBST[@src.matched] + if val.kind_of?(Symbol) + @tree.children << Element.new(:typographic_sym, val, nil, location: start_line_number) + elsif @src.matched == '\\<<' + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('lt'), + nil, location: start_line_number) + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('lt'), + nil, location: start_line_number) + else + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('gt'), + nil, location: start_line_number) + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('gt'), + nil, location: start_line_number) + end + end + define_parser(:typographic_syms, TYPOGRAPHIC_SYMS_RE, '--|\\.\\.\\.|(?:\\\\| )?(?:<<|>>)') + + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/markdown.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/markdown.rb new file mode 100644 index 0000000..9f36758 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/parser/markdown.rb @@ -0,0 +1,57 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser' + +module Kramdown + + module Parser + + # Used for parsing a document in Markdown format. + # + # This parser is based on the kramdown parser and removes the parser methods for the additional + # non-Markdown features. However, since some things are handled differently by the kramdown + # parser methods (like deciding when a list item contains just text), this parser differs from + # real Markdown parsers in some respects. + # + # Note, though, that the parser basically fails just one of the Markdown test cases (some others + # also fail but those failures are negligible). + class Markdown < Kramdown + + # Array with all the parsing methods that should be removed from the standard kramdown parser. + EXTENDED = [:codeblock_fenced, :table, :definition_list, :footnote_definition, + :abbrev_definition, :block_math, :block_extensions, + :footnote_marker, :smart_quotes, :inline_math, :span_extensions, :typographic_syms] + + def initialize(source, options) # :nodoc: + super + @block_parsers.delete_if {|i| EXTENDED.include?(i) } + @span_parsers.delete_if {|i| EXTENDED.include?(i) } + end + + # :stopdoc: + + BLOCK_BOUNDARY = /#{BLANK_LINE}|#{EOB_MARKER}|\Z/ + LAZY_END = /#{BLANK_LINE}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}| + ^#{OPT_SPACE}#{LAZY_END_HTML_START}|\Z/x + CODEBLOCK_MATCH = /(?:#{BLANK_LINE}?(?:#{INDENT}[ \t]*\S.*\n)+)*/ + PARAGRAPH_END = LAZY_END + + IAL_RAND_CHARS = (('a'..'z').to_a + ('0'..'9').to_a) + IAL_RAND_STRING = (1..20).collect { IAL_RAND_CHARS[rand(IAL_RAND_CHARS.size)] }.join + LIST_ITEM_IAL = /^\s*(#{IAL_RAND_STRING})?\s*\n/ + IAL_SPAN_START = LIST_ITEM_IAL + + # :startdoc: + + end + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils.rb new file mode 100644 index 0000000..5928def --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils.rb @@ -0,0 +1,45 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # == \Utils Module + # + # This module contains utility class/modules/methods that can be used by both parsers and + # converters. + module Utils + + autoload :Entities, 'kramdown/utils/entities' + autoload :Html, 'kramdown/utils/html' + autoload :Unidecoder, 'kramdown/utils/unidecoder' + autoload :StringScanner, 'kramdown/utils/string_scanner' + autoload :Configurable, 'kramdown/utils/configurable' + autoload :LRUCache, 'kramdown/utils/lru_cache' + + # Treat +name+ as if it were snake cased (e.g. snake_case) and camelize it (e.g. SnakeCase). + def self.camelize(name) + name.split('_').inject(+'') {|s, x| s << x[0..0].upcase << x[1..-1] } + end + + # Treat +name+ as if it were camelized (e.g. CamelizedName) and snake-case it (e.g. camelized_name). + def self.snake_case(name) + name = name.dup + name.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2') + name.gsub!(/([a-z])([A-Z])/, '\1_\2') + name.downcase! + name + end + + def self.deep_const_get(str) + ::Object.const_get(str) + end + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/configurable.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/configurable.rb new file mode 100644 index 0000000..2989493 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/configurable.rb @@ -0,0 +1,45 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Utils + + # Methods for registering configurable extensions. + module Configurable + + # Create a new configurable extension called +name+. + # + # Three methods will be defined on the calling object which allow to use this configurable + # extension: + # + # configurables:: Returns a hash of hashes that is used to store all configurables of the + # object. + # + # <name>(ext_name):: Return the configured extension +ext_name+. + # + # add_<name>(ext_name, data=nil, &block):: Define an extension +ext_name+ by specifying either + # the data as argument or by using a block. + def configurable(name) + unless respond_to?(:configurables) + singleton_class.send(:define_method, :configurables) do + @_configurables ||= Hash.new {|h, k| h[k] = {} } + end + end + singleton_class.send(:define_method, name) do |data| + configurables[name][data] + end + singleton_class.send(:define_method, "add_#{name}".intern) do |data, *args, &block| + configurables[name][data] = args.first || block + end + end + + end + + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/entities.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/entities.rb new file mode 100644 index 0000000..156dd76 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/entities.rb @@ -0,0 +1,1000 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + module Utils + + # Provides convenience methods for handling named and numeric entities. + module Entities + + # Represents an entity that has a +code_point+ and +name+. + Entity = Struct.new(:code_point, :name) do + # Return the UTF8 representation of the entity. + def char + [code_point].pack('U*') rescue nil + end + end + + # Array of arrays. Each sub-array specifies a code point and the associated name. + # + # This table is not used directly -- Entity objects are automatically created from it and put + # into a Hash map when this file is loaded. + ENTITY_TABLE = [ + + # html4 + [913, 'Alpha'], + [914, 'Beta'], + [915, 'Gamma'], + [916, 'Delta'], + [917, 'Epsilon'], + [918, 'Zeta'], + [919, 'Eta'], + [920, 'Theta'], + [921, 'Iota'], + [922, 'Kappa'], + [923, 'Lambda'], + [924, 'Mu'], + [925, 'Nu'], + [926, 'Xi'], + [927, 'Omicron'], + [928, 'Pi'], + [929, 'Rho'], + [931, 'Sigma'], + [932, 'Tau'], + [933, 'Upsilon'], + [934, 'Phi'], + [935, 'Chi'], + [936, 'Psi'], + [937, 'Omega'], + [945, 'alpha'], + [946, 'beta'], + [947, 'gamma'], + [948, 'delta'], + [949, 'epsilon'], + [950, 'zeta'], + [951, 'eta'], + [952, 'theta'], + [953, 'iota'], + [954, 'kappa'], + [955, 'lambda'], + [956, 'mu'], + [957, 'nu'], + [958, 'xi'], + [959, 'omicron'], + [960, 'pi'], + [961, 'rho'], + [963, 'sigma'], + [964, 'tau'], + [965, 'upsilon'], + [966, 'phi'], + [967, 'chi'], + [968, 'psi'], + [969, 'omega'], + [962, 'sigmaf'], + [977, 'thetasym'], + [978, 'upsih'], + [982, 'piv'], + [988, 'Gammad'], + [989, 'gammad'], + [8204, 'zwnj'], + [8205, 'zwj'], + [8206, 'lrm'], + [8207, 'rlm'], + [8230, 'hellip'], + [8242, 'prime'], + [8243, 'Prime'], + [8254, 'oline'], + [8260, 'frasl'], + [8472, 'weierp'], + [8465, 'image'], + [8476, 'real'], + [8501, 'alefsym'], + [8226, 'bull'], + [8482, 'trade'], + [8592, 'larr'], + [8594, 'rarr'], + [8593, 'uarr'], + [8595, 'darr'], + [8596, 'harr'], + [8629, 'crarr'], + [8657, 'uArr'], + [8659, 'dArr'], + [8656, 'lArr'], + [8658, 'rArr'], + [8660, 'hArr'], + [8704, 'forall'], + [8706, 'part'], + [8707, 'exist'], + [8709, 'empty'], + [8711, 'nabla'], + [8712, 'isin'], + [8715, 'ni'], + [8713, 'notin'], + [8721, 'sum'], + [8719, 'prod'], + [8722, 'minus'], + [8727, 'lowast'], + [8730, 'radic'], + [8733, 'prop'], + [8734, 'infin'], + [8736, 'ang'], + [8743, 'and'], + [8744, 'or'], + [8745, 'cap'], + [8746, 'cup'], + [8747, 'int'], + [8756, 'there4'], + [8764, 'sim'], + [8776, 'asymp'], + [8773, 'cong'], + [8800, 'ne'], + [8801, 'equiv'], + [8804, 'le'], + [8805, 'ge'], + [8834, 'sub'], + [8835, 'sup'], + [8838, 'sube'], + [8839, 'supe'], + [8836, 'nsub'], + [8853, 'oplus'], + [8855, 'otimes'], + [8869, 'perp'], + [8901, 'sdot'], + [8942, 'vellip'], + [8968, 'rceil'], + [8969, 'lceil'], + [8970, 'lfloor'], + [8971, 'rfloor'], + [9001, 'rang'], + [9002, 'lang'], + [9674, 'loz'], + [9824, 'spades'], + [9827, 'clubs'], + [9829, 'hearts'], + [9830, 'diams'], + [38, 'amp'], + [34, 'quot'], + [39, 'apos'], + [169, 'copy'], + [60, 'lt'], + [62, 'gt'], + [338, 'OElig'], + [339, 'oelig'], + [352, 'Scaron'], + [353, 'scaron'], + [376, 'Yuml'], + [710, 'circ'], + [732, 'tilde'], + [8211, 'ndash'], + [8212, 'mdash'], + [8216, 'lsquo'], + [8217, 'rsquo'], + [8220, 'ldquo'], + [8221, 'rdquo'], + [8224, 'dagger'], + [8225, 'Dagger'], + [8240, 'permil'], + [8364, 'euro'], + [8249, 'lsaquo'], + [8250, 'rsaquo'], + [160, 'nbsp'], + [161, 'iexcl'], + [163, 'pound'], + [164, 'curren'], + [165, 'yen'], + [166, 'brvbar'], + [167, 'sect'], + [168, 'uml'], + [171, 'laquo'], + [187, 'raquo'], + [174, 'reg'], + [170, 'ordf'], + [172, 'not'], + [173, 'shy'], + [175, 'macr'], + [176, 'deg'], + [177, 'plusmn'], + [180, 'acute'], + [181, 'micro'], + [182, 'para'], + [183, 'middot'], + [184, 'cedil'], + [186, 'ordm'], + [162, 'cent'], + [185, 'sup1'], + [178, 'sup2'], + [179, 'sup3'], + [189, 'frac12'], + [188, 'frac14'], + [190, 'frac34'], + [8531, 'frac13'], + [8532, 'frac23'], + [8533, 'frac15'], + [8534, 'frac25'], + [8535, 'frac35'], + [8536, 'frac45'], + [8537, 'frac16'], + [8538, 'frac56'], + [8539, 'frac18'], + [8540, 'frac38'], + [8541, 'frac58'], + [8542, 'frac78'], + [191, 'iquest'], + [192, 'Agrave'], + [193, 'Aacute'], + [194, 'Acirc'], + [195, 'Atilde'], + [196, 'Auml'], + [197, 'Aring'], + [198, 'AElig'], + [199, 'Ccedil'], + [200, 'Egrave'], + [201, 'Eacute'], + [202, 'Ecirc'], + [203, 'Euml'], + [204, 'Igrave'], + [205, 'Iacute'], + [206, 'Icirc'], + [207, 'Iuml'], + [208, 'ETH'], + [209, 'Ntilde'], + [210, 'Ograve'], + [211, 'Oacute'], + [212, 'Ocirc'], + [213, 'Otilde'], + [214, 'Ouml'], + [215, 'times'], + [216, 'Oslash'], + [217, 'Ugrave'], + [218, 'Uacute'], + [219, 'Ucirc'], + [220, 'Uuml'], + [221, 'Yacute'], + [222, 'THORN'], + [223, 'szlig'], + [224, 'agrave'], + [225, 'aacute'], + [226, 'acirc'], + [227, 'atilde'], + [228, 'auml'], + [229, 'aring'], + [230, 'aelig'], + [231, 'ccedil'], + [232, 'egrave'], + [233, 'eacute'], + [234, 'ecirc'], + [235, 'euml'], + [236, 'igrave'], + [237, 'iacute'], + [238, 'icirc'], + [239, 'iuml'], + [240, 'eth'], + [241, 'ntilde'], + [242, 'ograve'], + [243, 'oacute'], + [244, 'ocirc'], + [245, 'otilde'], + [246, 'ouml'], + [247, 'divide'], + [248, 'oslash'], + [249, 'ugrave'], + [250, 'uacute'], + [251, 'ucirc'], + [252, 'uuml'], + [253, 'yacute'], + [254, 'thorn'], + [255, 'yuml'], + + [8218, 'sbquo'], + [402, 'fnof'], + [8222, 'bdquo'], + + [128, 8364], + [130, 8218], + [131, 402], + [132, 8222], + [133, 8230], + [134, 8224], + [135, 8225], + [136, 710], + [137, 8240], + [138, 352], + [139, 8249], + [140, 338], + [142, 381], + [145, 8216], + [146, 8217], + [147, 8220], + [148, 8221], + [149, 8226], + [150, 8211], + [151, 8212], + [152, 732], + [153, 8482], + [154, 353], + [155, 8250], + [156, 339], + [158, 382], + [159, 376], + + [8194, 'ensp'], + [8195, 'emsp'], + [8201, 'thinsp'], + + # html5 + [10218, 'Lang'], + [10219, 'Rang'], + [10220, 'loang'], + [10221, 'roang'], + [10229, 'xlarr'], + [10229, 'longleftarrow'], + [10229, 'LongLeftArrow'], + [10230, 'xrarr'], + [10230, 'longrightarrow'], + [10230, 'LongRightArrow'], + [10231, 'xharr'], + [10231, 'longleftrightarrow'], + [10231, 'LongLeftRightArrow'], + [10232, 'xlArr'], + [10232, 'Longleftarrow'], + [10232, 'DoubleLongLeftArrow'], + [10233, 'xrArr'], + [10233, 'Longrightarrow'], + [10233, 'DoubleLongRightArrow'], + [10234, 'xhArr'], + [10234, 'Longleftrightarrow'], + [10234, 'DoubleLongLeftRightArrow'], + [10236, 'xmap'], + [10236, 'longmapsto'], + [10239, 'dzigrarr'], + [10498, 'nvlArr'], + [10499, 'nvrArr'], + [10500, 'nvHarr'], + [10501, 'Map'], + [10508, 'lbarr'], + [10509, 'rbarr'], + [10509, 'bkarow'], + [10510, 'lBarr'], + [10511, 'rBarr'], + [10511, 'dbkarow'], + [10512, 'RBarr'], + [10512, 'drbkarow'], + [10513, 'DDotrahd'], + [10514, 'UpArrowBar'], + [10515, 'DownArrowBar'], + [10518, 'Rarrtl'], + [10521, 'latail'], + [10522, 'ratail'], + [10523, 'lAtail'], + [10524, 'rAtail'], + [10525, 'larrfs'], + [10526, 'rarrfs'], + [10527, 'larrbfs'], + [10528, 'rarrbfs'], + [10531, 'nwarhk'], + [10532, 'nearhk'], + [10533, 'searhk'], + [10533, 'hksearow'], + [10534, 'swarhk'], + [10534, 'hkswarow'], + [10535, 'nwnear'], + [10536, 'nesear'], + [10536, 'toea'], + [10537, 'seswar'], + [10537, 'tosa'], + [10538, 'swnwar'], + [10547, 'rarrc'], + [10549, 'cudarrr'], + [10550, 'ldca'], + [10551, 'rdca'], + [10552, 'cudarrl'], + [10553, 'larrpl'], + [10556, 'curarrm'], + [10557, 'cularrp'], + [10565, 'rarrpl'], + [10568, 'harrcir'], + [10569, 'Uarrocir'], + [10570, 'lurdshar'], + [10571, 'ldrushar'], + [10574, 'LeftRightVector'], + [10575, 'RightUpDownVector'], + [10576, 'DownLeftRightVector'], + [10577, 'LeftUpDownVector'], + [10578, 'LeftVectorBar'], + [10579, 'RightVectorBar'], + [10580, 'RightUpVectorBar'], + [10581, 'RightDownVectorBar'], + [10582, 'DownLeftVectorBar'], + [10583, 'DownRightVectorBar'], + [10584, 'LeftUpVectorBar'], + [10585, 'LeftDownVectorBar'], + [10586, 'LeftTeeVector'], + [10587, 'RightTeeVector'], + [10588, 'RightUpTeeVector'], + [10589, 'RightDownTeeVector'], + [10590, 'DownLeftTeeVector'], + [10591, 'DownRightTeeVector'], + [10592, 'LeftUpTeeVector'], + [10593, 'LeftDownTeeVector'], + [10594, 'lHar'], + [10595, 'uHar'], + [10596, 'rHar'], + [10597, 'dHar'], + [10598, 'luruhar'], + [10599, 'ldrdhar'], + [10600, 'ruluhar'], + [10601, 'rdldhar'], + [10602, 'lharul'], + [10603, 'llhard'], + [10604, 'rharul'], + [10605, 'lrhard'], + [10606, 'udhar'], + [10606, 'UpEquilibrium'], + [10607, 'duhar'], + [10607, 'ReverseUpEquilibrium'], + [10608, 'RoundImplies'], + [10609, 'erarr'], + [10610, 'simrarr'], + [10611, 'larrsim'], + [10612, 'rarrsim'], + [10613, 'rarrap'], + [10614, 'ltlarr'], + [10616, 'gtrarr'], + [10617, 'subrarr'], + [10619, 'suplarr'], + [10620, 'lfisht'], + [10621, 'rfisht'], + [10622, 'ufisht'], + [10623, 'dfisht'], + [10629, 'lopar'], + [10630, 'ropar'], + [10635, 'lbrke'], + [10636, 'rbrke'], + [10637, 'lbrkslu'], + [10638, 'rbrksld'], + [10639, 'lbrksld'], + [10640, 'rbrkslu'], + [10641, 'langd'], + [10642, 'rangd'], + [10643, 'lparlt'], + [10644, 'rpargt'], + [10645, 'gtlPar'], + [10646, 'ltrPar'], + [10650, 'vzigzag'], + [10652, 'vangrt'], + [10653, 'angrtvbd'], + [10660, 'ange'], + [10661, 'range'], + [10662, 'dwangle'], + [10663, 'uwangle'], + [10664, 'angmsdaa'], + [10665, 'angmsdab'], + [10666, 'angmsdac'], + [10667, 'angmsdad'], + [10668, 'angmsdae'], + [10669, 'angmsdaf'], + [10670, 'angmsdag'], + [10671, 'angmsdah'], + [10672, 'bemptyv'], + [10673, 'demptyv'], + [10674, 'cemptyv'], + [10675, 'raemptyv'], + [10676, 'laemptyv'], + [10677, 'ohbar'], + [10678, 'omid'], + [10679, 'opar'], + [10681, 'operp'], + [10683, 'olcross'], + [10684, 'odsold'], + [10686, 'olcir'], + [10687, 'ofcir'], + [10688, 'olt'], + [10689, 'ogt'], + [10690, 'cirscir'], + [10691, 'cirE'], + [10692, 'solb'], + [10693, 'bsolb'], + [10697, 'boxbox'], + [10701, 'trisb'], + [10702, 'rtriltri'], + [10703, 'LeftTriangleBar'], + [10704, 'RightTriangleBar'], + [10716, 'iinfin'], + [10717, 'infintie'], + [10718, 'nvinfin'], + [10723, 'eparsl'], + [10724, 'smeparsl'], + [10725, 'eqvparsl'], + [10731, 'lozf'], + [10731, 'blacklozenge'], + [10740, 'RuleDelayed'], + [10742, 'dsol'], + [10752, 'xodot'], + [10752, 'bigodot'], + [10753, 'xoplus'], + [10753, 'bigoplus'], + [10754, 'xotime'], + [10754, 'bigotimes'], + [10756, 'xuplus'], + [10756, 'biguplus'], + [10758, 'xsqcup'], + [10758, 'bigsqcup'], + [10764, 'qint'], + [10764, 'iiiint'], + [10765, 'fpartint'], + [10768, 'cirfnint'], + [10769, 'awint'], + [10770, 'rppolint'], + [10771, 'scpolint'], + [10772, 'npolint'], + [10773, 'pointint'], + [10774, 'quatint'], + [10775, 'intlarhk'], + [10786, 'pluscir'], + [10787, 'plusacir'], + [10788, 'simplus'], + [10789, 'plusdu'], + [10790, 'plussim'], + [10791, 'plustwo'], + [10793, 'mcomma'], + [10794, 'minusdu'], + [10797, 'loplus'], + [10798, 'roplus'], + [10799, 'Cross'], + [10800, 'timesd'], + [10801, 'timesbar'], + [10803, 'smashp'], + [10804, 'lotimes'], + [10805, 'rotimes'], + [10806, 'otimesas'], + [10807, 'Otimes'], + [10808, 'odiv'], + [10809, 'triplus'], + [10810, 'triminus'], + [10811, 'tritime'], + [10812, 'iprod'], + [10812, 'intprod'], + [10815, 'amalg'], + [10816, 'capdot'], + [10818, 'ncup'], + [10819, 'ncap'], + [10820, 'capand'], + [10821, 'cupor'], + [10822, 'cupcap'], + [10823, 'capcup'], + [10824, 'cupbrcap'], + [10825, 'capbrcup'], + [10826, 'cupcup'], + [10827, 'capcap'], + [10828, 'ccups'], + [10829, 'ccaps'], + [10832, 'ccupssm'], + [10835, 'And'], + [10836, 'Or'], + [10837, 'andand'], + [10838, 'oror'], + [10839, 'orslope'], + [10840, 'andslope'], + [10842, 'andv'], + [10843, 'orv'], + [10844, 'andd'], + [10845, 'ord'], + [10847, 'wedbar'], + [10854, 'sdote'], + [10858, 'simdot'], + [10861, 'congdot'], + [10862, 'easter'], + [10863, 'apacir'], + [10864, 'apE'], + [10865, 'eplus'], + [10866, 'pluse'], + [10867, 'Esim'], + [10868, 'Colone'], + [10869, 'Equal'], + [10871, 'eDDot'], + [10871, 'ddotseq'], + [10872, 'equivDD'], + [10873, 'ltcir'], + [10874, 'gtcir'], + [10875, 'ltquest'], + [10876, 'gtquest'], + [10877, 'les'], + [10877, 'LessSlantEqual'], + [10877, 'leqslant'], + [10878, 'ges'], + [10878, 'GreaterSlantEqual'], + [10878, 'geqslant'], + [10879, 'lesdot'], + [10880, 'gesdot'], + [10881, 'lesdoto'], + [10882, 'gesdoto'], + [10883, 'lesdotor'], + [10884, 'gesdotol'], + [10885, 'lap'], + [10885, 'lessapprox'], + [10886, 'gap'], + [10886, 'gtrapprox'], + [10887, 'lne'], + [10887, 'lneq'], + [10888, 'gne'], + [10888, 'gneq'], + [10889, 'lnap'], + [10889, 'lnapprox'], + [10890, 'gnap'], + [10890, 'gnapprox'], + [10891, 'lEg'], + [10891, 'lesseqqgtr'], + [10892, 'gEl'], + [10892, 'gtreqqless'], + [10893, 'lsime'], + [10894, 'gsime'], + [10895, 'lsimg'], + [10896, 'gsiml'], + [10897, 'lgE'], + [10898, 'glE'], + [10899, 'lesges'], + [10900, 'gesles'], + [10901, 'els'], + [10901, 'eqslantless'], + [10902, 'egs'], + [10902, 'eqslantgtr'], + [10903, 'elsdot'], + [10904, 'egsdot'], + [10905, 'el'], + [10906, 'eg'], + [10909, 'siml'], + [10910, 'simg'], + [10911, 'simlE'], + [10912, 'simgE'], + [10913, 'LessLess'], + [10914, 'GreaterGreater'], + [10916, 'glj'], + [10917, 'gla'], + [10918, 'ltcc'], + [10919, 'gtcc'], + [10920, 'lescc'], + [10921, 'gescc'], + [10922, 'smt'], + [10923, 'lat'], + [10924, 'smte'], + [10925, 'late'], + [10926, 'bumpE'], + [10927, 'pre'], + [10927, 'preceq'], + [10927, 'PrecedesEqual'], + [10928, 'sce'], + [10928, 'succeq'], + [10928, 'SucceedsEqual'], + [10931, 'prE'], + [10932, 'scE'], + [10933, 'prnE'], + [10933, 'precneqq'], + [10934, 'scnE'], + [10934, 'succneqq'], + [10935, 'prap'], + [10935, 'precapprox'], + [10936, 'scap'], + [10936, 'succapprox'], + [10937, 'prnap'], + [10937, 'precnapprox'], + [10938, 'scnap'], + [10938, 'succnapprox'], + [10939, 'Pr'], + [10940, 'Sc'], + [10941, 'subdot'], + [10942, 'supdot'], + [10943, 'subplus'], + [10944, 'supplus'], + [10945, 'submult'], + [10946, 'supmult'], + [10947, 'subedot'], + [10948, 'supedot'], + [10949, 'subE'], + [10949, 'subseteqq'], + [10950, 'supE'], + [10950, 'supseteqq'], + [10951, 'subsim'], + [10952, 'supsim'], + [10955, 'subnE'], + [10955, 'subsetneqq'], + [10956, 'supnE'], + [10956, 'supsetneqq'], + [10959, 'csub'], + [10960, 'csup'], + [10961, 'csube'], + [10962, 'csupe'], + [10963, 'subsup'], + [10964, 'supsub'], + [10965, 'subsub'], + [10966, 'supsup'], + [10967, 'suphsub'], + [10968, 'supdsub'], + [10969, 'forkv'], + [10970, 'topfork'], + [10971, 'mlcp'], + [10980, 'Dashv'], + [10980, 'DoubleLeftTee'], + [10982, 'Vdashl'], + [10983, 'Barv'], + [10984, 'vBar'], + [10985, 'vBarv'], + [10987, 'Vbar'], + [10988, 'Not'], + [10989, 'bNot'], + [10990, 'rnmid'], + [10991, 'cirmid'], + [10992, 'midcir'], + [10993, 'topcir'], + [10994, 'nhpar'], + [10995, 'parsim'], + [11005, 'parsl'], + [64256, 'fflig'], + [64257, 'filig'], + [64258, 'fllig'], + [64259, 'ffilig'], + [64260, 'ffllig'], + [119964, 'Ascr'], + [119966, 'Cscr'], + [119967, 'Dscr'], + [119970, 'Gscr'], + [119973, 'Jscr'], + [119974, 'Kscr'], + [119977, 'Nscr'], + [119978, 'Oscr'], + [119979, 'Pscr'], + [119980, 'Qscr'], + [119982, 'Sscr'], + [119983, 'Tscr'], + [119984, 'Uscr'], + [119985, 'Vscr'], + [119986, 'Wscr'], + [119987, 'Xscr'], + [119988, 'Yscr'], + [119989, 'Zscr'], + [119990, 'ascr'], + [119991, 'bscr'], + [119992, 'cscr'], + [119993, 'dscr'], + [119995, 'fscr'], + [119997, 'hscr'], + [119998, 'iscr'], + [119999, 'jscr'], + [120000, 'kscr'], + [120001, 'lscr'], + [120002, 'mscr'], + [120003, 'nscr'], + [120005, 'pscr'], + [120006, 'qscr'], + [120007, 'rscr'], + [120008, 'sscr'], + [120009, 'tscr'], + [120010, 'uscr'], + [120011, 'vscr'], + [120012, 'wscr'], + [120013, 'xscr'], + [120014, 'yscr'], + [120015, 'zscr'], + [120068, 'Afr'], + [120069, 'Bfr'], + [120071, 'Dfr'], + [120072, 'Efr'], + [120073, 'Ffr'], + [120074, 'Gfr'], + [120077, 'Jfr'], + [120078, 'Kfr'], + [120079, 'Lfr'], + [120080, 'Mfr'], + [120081, 'Nfr'], + [120082, 'Ofr'], + [120083, 'Pfr'], + [120084, 'Qfr'], + [120086, 'Sfr'], + [120087, 'Tfr'], + [120088, 'Ufr'], + [120089, 'Vfr'], + [120090, 'Wfr'], + [120091, 'Xfr'], + [120092, 'Yfr'], + [120094, 'afr'], + [120095, 'bfr'], + [120096, 'cfr'], + [120097, 'dfr'], + [120098, 'efr'], + [120099, 'ffr'], + [120100, 'gfr'], + [120101, 'hfr'], + [120102, 'ifr'], + [120103, 'jfr'], + [120104, 'kfr'], + [120105, 'lfr'], + [120106, 'mfr'], + [120107, 'nfr'], + [120108, 'ofr'], + [120109, 'pfr'], + [120110, 'qfr'], + [120111, 'rfr'], + [120112, 'sfr'], + [120113, 'tfr'], + [120114, 'ufr'], + [120115, 'vfr'], + [120116, 'wfr'], + [120117, 'xfr'], + [120118, 'yfr'], + [120119, 'zfr'], + [120120, 'Aopf'], + [120121, 'Bopf'], + [120123, 'Dopf'], + [120124, 'Eopf'], + [120125, 'Fopf'], + [120126, 'Gopf'], + [120128, 'Iopf'], + [120129, 'Jopf'], + [120130, 'Kopf'], + [120131, 'Lopf'], + [120132, 'Mopf'], + [120134, 'Oopf'], + [120138, 'Sopf'], + [120139, 'Topf'], + [120140, 'Uopf'], + [120141, 'Vopf'], + [120142, 'Wopf'], + [120143, 'Xopf'], + [120144, 'Yopf'], + [120146, 'aopf'], + [120147, 'bopf'], + [120148, 'copf'], + [120149, 'dopf'], + [120150, 'eopf'], + [120151, 'fopf'], + [120152, 'gopf'], + [120153, 'hopf'], + [120154, 'iopf'], + [120155, 'jopf'], + [120156, 'kopf'], + [120157, 'lopf'], + [120158, 'mopf'], + [120159, 'nopf'], + [120160, 'oopf'], + [120161, 'popf'], + [120162, 'qopf'], + [120163, 'ropf'], + [120164, 'sopf'], + [120165, 'topf'], + [120166, 'uopf'], + [120167, 'vopf'], + [120168, 'wopf'], + [120169, 'xopf'], + [120170, 'yopf'], + [120171, 'zopf'], + [60, 'nvlt'], + [61, 'bne'], + [62, 'nvgt'], + [102, 'fjlig'], + [8287, 'ThickSpace'], + [8605, 'nrarrw'], + [8706, 'npart'], + [8736, 'nang'], + [8745, 'caps'], + [8746, 'cups'], + [8764, 'nvsim'], + [8765, 'race'], + [8766, 'acE'], + [8770, 'nesim'], + [8770, 'NotEqualTilde'], + [8779, 'napid'], + [8781, 'nvap'], + [8782, 'nbump'], + [8782, 'NotHumpDownHump'], + [8783, 'nbumpe'], + [8783, 'NotHumpEqual'], + [8784, 'nedot'], + [8801, 'bnequiv'], + [8804, 'nvle'], + [8805, 'nvge'], + [8806, 'nlE'], + [8806, 'nleqq'], + [8807, 'ngE'], + [8807, 'ngeqq'], + [8807, 'NotGreaterFullEqual'], + [8808, 'lvertneqq'], + [8808, 'lvnE'], + [8809, 'gvertneqq'], + [8809, 'gvnE'], + [8810, 'nLtv'], + [8810, 'NotLessLess'], + [8810, 'nLt'], + [8811, 'nGtv'], + [8811, 'NotGreaterGreater'], + [8811, 'nGt'], + [8831, 'NotSucceedsTilde'], + [8834, 'NotSubset'], + [8834, 'nsubset'], + [8834, 'vnsub'], + [8835, 'NotSuperset'], + [8835, 'nsupset'], + [8835, 'vnsup'], + [8842, 'varsubsetneq'], + [8842, 'vsubne'], + [8843, 'varsupsetneq'], + [8843, 'vsupne'], + [8847, 'NotSquareSubset'], + [8848, 'NotSquareSuperset'], + [8851, 'sqcaps'], + [8852, 'sqcups'], + [8884, 'nvltrie'], + [8885, 'nvrtrie'], + [8920, 'nLl'], + [8921, 'nGg'], + [8922, 'lesg'], + [8923, 'gesl'], + [8949, 'notindot'], + [8953, 'notinE'], + [10547, 'nrarrc'], + [10703, 'NotLeftTriangleBar'], + [10704, 'NotRightTriangleBar'], + [10861, 'ncongdot'], + [10864, 'napE'], + [10877, 'nleqslant'], + [10877, 'nles'], + [10877, 'NotLessSlantEqual'], + [10878, 'ngeqslant'], + [10878, 'nges'], + [10878, 'NotGreaterSlantEqual'], + [10913, 'NotNestedLessLess'], + [10914, 'NotNestedGreaterGreater'], + [10924, 'smtes'], + [10925, 'lates'], + [10927, 'NotPrecedesEqual'], + [10927, 'npre'], + [10927, 'npreceq'], + [10928, 'NotSucceedsEqual'], + [10928, 'nsce'], + [10928, 'nsucceq'], + [10949, 'nsubE'], + [10949, 'nsubseteqq'], + [10950, 'nsupE'], + [10950, 'nsupseteqq'], + [10955, 'varsubsetneqq'], + [10955, 'vsubnE'], + [10956, 'varsupsetneqq'], + [10956, 'vsupnE'], + [11005, 'nparsl'], + + ] + + # Contains the mapping of code point (or name) to the actual Entity object. + ENTITY_MAP = Hash.new do |h, k| + if k.kind_of?(Integer) + h[k] = Entity.new(k, nil) + else + raise Kramdown::Error, "Can't handle generic non-integer character reference '#{k}'" + end + end + + ENTITY_TABLE.each do |code_point, data| + ENTITY_MAP[code_point] = if data.kind_of?(String) + ENTITY_MAP[data] = Entity.new(code_point, data) + else + ENTITY_MAP[data] + end + end + + # Return the entity for the given code point or name +point_or_name+. + def entity(point_or_name) + ENTITY_MAP[point_or_name] + end + + module_function :entity + + end + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/html.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/html.rb new file mode 100644 index 0000000..0fba9d4 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/html.rb @@ -0,0 +1,84 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'rexml/parsers/baseparser' + +module Kramdown + + module Utils + + # Provides convenience methods for HTML related tasks. + # + # *Note* that this module has to be mixed into a class that has a @root (containing an element + # of type :root) and an @options (containing an options hash) instance variable so that some of + # the methods can work correctly. + module Html + + # Convert the entity +e+ to a string. The optional parameter +original+ may contain the + # original representation of the entity. + # + # This method uses the option +entity_output+ to determine the output form for the entity. + def entity_to_str(e, original = nil) + entity_output = @options[:entity_output] + + if entity_output == :as_char && + (c = e.char.encode(@root.options[:encoding]) rescue nil) && + ((c = e.char) == '"' || !ESCAPE_MAP.key?(c)) + c + elsif (entity_output == :as_input || entity_output == :as_char) && original + original + elsif (entity_output == :symbolic || ESCAPE_MAP.key?(e.char)) && !e.name.nil? + "&#{e.name};" + else # default to :numeric + "&##{e.code_point};" + end + end + + # Return the HTML representation of the attributes +attr+. + def html_attributes(attr) + return '' if attr.empty? + + attr.map do |k, v| + v.nil? || (k == 'id' && v.strip.empty?) ? '' : " #{k}=\"#{escape_html(v.to_s, :attribute)}\"" + end.join + end + + # :stopdoc: + ESCAPE_MAP = { + '<' => '<', + '>' => '>', + '&' => '&', + '"' => '"', + } + ESCAPE_ALL_RE = /<|>|&/ + ESCAPE_TEXT_RE = Regexp.union(REXML::Parsers::BaseParser::REFERENCE_RE, /<|>|&/) + ESCAPE_ATTRIBUTE_RE = Regexp.union(REXML::Parsers::BaseParser::REFERENCE_RE, /<|>|&|"/) + ESCAPE_RE_FROM_TYPE = {all: ESCAPE_ALL_RE, text: ESCAPE_TEXT_RE, attribute: ESCAPE_ATTRIBUTE_RE} + # :startdoc: + + # Escape the special HTML characters in the string +str+. The parameter +type+ specifies what + # is escaped: :all - all special HTML characters except the quotation mark as well as + # entities, :text - all special HTML characters except the quotation mark but no entities and + # :attribute - all special HTML characters including the quotation mark but no entities. + def escape_html(str, type = :all) + str.gsub(ESCAPE_RE_FROM_TYPE[type]) {|m| ESCAPE_MAP[m] || m } + end + + REDUNDANT_LINE_BREAK_REGEX = /([\p{Han}\p{Hiragana}\p{Katakana}]+)\n([\p{Han}\p{Hiragana}\p{Katakana}]+)/u + def fix_cjk_line_break(str) + while str.gsub!(REDUNDANT_LINE_BREAK_REGEX, '\1\2') + end + str + end + + end + + end + +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/lru_cache.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/lru_cache.rb new file mode 100644 index 0000000..32549fb --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/lru_cache.rb @@ -0,0 +1,41 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Utils + + # A simple least recently used (LRU) cache. + # + # The cache relies on the fact that Ruby's Hash class maintains insertion order. So deleting + # and re-inserting a key-value pair on access moves the key to the last position. When an + # entry is added and the cache is full, the first entry is removed. + class LRUCache + + # Creates a new LRUCache that can hold +size+ entries. + def initialize(size) + @size = size + @cache = {} + end + + # Returns the stored value for +key+ or +nil+ if no value was stored under the key. + def [](key) + (val = @cache.delete(key)).nil? ? nil : @cache[key] = val + end + + # Stores the +value+ under the +key+. + def []=(key, value) + @cache.delete(key) + @cache[key] = value + @cache.shift if @cache.length > @size + end + + end + + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/string_scanner.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/string_scanner.rb new file mode 100644 index 0000000..2ef194e --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/string_scanner.rb @@ -0,0 +1,81 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'strscan' + +module Kramdown + module Utils + + # This patched StringScanner adds line number information for current scan position and a + # start_line_number override for nested StringScanners. + class StringScanner < ::StringScanner + + # The start line number. Used for nested StringScanners that scan a sub-string of the source + # document. The kramdown parser uses this, e.g., for span level parsers. + attr_reader :start_line_number + + # Takes the start line number as optional second argument. + # + # Note: The original second argument is no longer used so this should be safe. + def initialize(string, start_line_number = 1) + super(string) + @start_line_number = start_line_number || 1 + @previous_pos = 0 + @previous_line_number = @start_line_number + end + + # Sets the byte position of the scan pointer. + # + # Note: This also resets some internal variables, so always use pos= when setting the position + # and don't use any other method for that! + def pos=(pos) + if self.pos > pos + @previous_line_number = @start_line_number + @previous_pos = 0 + end + super + end + + # Return information needed to revert the byte position of the string scanner in a performant + # way. + # + # The returned data can be fed to #revert_pos to revert the position to the saved one. + # + # Note: Just saving #pos won't be enough. + def save_pos + [pos, @previous_pos, @previous_line_number] + end + + # Revert the position to one saved by #save_pos. + def revert_pos(data) + self.pos = data[0] + @previous_pos, @previous_line_number = data[1], data[2] + end + + # Returns the line number for current charpos. + # + # NOTE: Requires that all line endings are normalized to '\n' + # + # NOTE: Normally we'd have to add one to the count of newlines to get the correct line number. + # However we add the one indirectly by using a one-based start_line_number. + def current_line_number + # Not using string[@previous_pos..best_pos].count('\n') because it is slower + strscan = ::StringScanner.new(string) + strscan.pos = @previous_pos + old_pos = pos + 1 + @previous_line_number += 1 while strscan.skip_until(/\n/) && strscan.pos <= old_pos + + @previous_pos = (eos? ? pos : pos + 1) + @previous_line_number + end + + end + + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/unidecoder.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/unidecoder.rb new file mode 100644 index 0000000..b4bbe28 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/utils/unidecoder.rb @@ -0,0 +1,46 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# +# This file is based on code originally from the Stringex library and needs the data files from +# Stringex to work correctly. + +module Kramdown + module Utils + + # Provides the ability to tranliterate Unicode strings into plain ASCII ones. + module Unidecoder + + gem 'stringex' + path = $:.find do |dir| + File.directory?(File.join(File.expand_path(dir), "stringex", "unidecoder_data")) + end + + if path + CODEPOINTS = Hash.new do |h, k| + h[k] = YAML.load_file(File.join(path, "stringex", "unidecoder_data", "#{k}.yml")) + end + + # Transliterate string from Unicode into ASCII. + def self.decode(string) + string.gsub(/[^\x00-\x7f]/u) do |codepoint| + unpacked = codepoint.unpack1("U") + CODEPOINTS[sprintf("x%02x", unpacked >> 8)][unpacked & 255] + rescue StandardError + "?" + end + end + else + def self.decode(string) + string + end + end + + end + + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/version.rb b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/version.rb new file mode 100644 index 0000000..0bc4130 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/kramdown-2.5.1/lib/kramdown/version.rb @@ -0,0 +1,15 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at> +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # The kramdown version. + VERSION = '2.5.1' + +end |
