Class: YARD::Templates::Helpers::Markup::HybridMarkdown
| Relationships & Source Files | |
| Inherits: | Object |
| Defined in: | lib/yard/templates/helpers/markup/hybrid_markdown.rb |
Overview
A built-in formatter that implements a practical subset of GitHub flavored Markdown plus common RDoc markup forms.
Constant Summary
-
ATX_HEADING_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 32/^\s{0,3}#{Regexp.escape('#')}{1,6}(?=[ \t]|$)/.freeze
-
AUTOLINK_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 83/<([A-Za-z][A-Za-z0-9.+-]{1,31}:[^<>\s]*|[A-Za-z0-9.!#$%&'*+\/=?^_`{|}~-]+@[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)+)>/.freeze
-
BLOCKQUOTE_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 43/^\s{0,3}>\s?(.*)$/.freeze
-
CODE_LANG_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 78/\A(?:[ \t]*\n)?[ \t]*!!!([\w.+-]+)[ \t]*\n/.freeze
-
ENTITY_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 76/&(?:[A-Za-z][A-Za-z0-9]+|#\d+|#[xX][0-9A-Fa-f]+);/.freeze
-
ESCAPABLE_CHARS_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 81/\\([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])/.freeze
-
FENCE_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 35/^(\s{0,3})(`{3,}|~{3,})([^\n]*)$/.freeze
-
HTML_BLOCK_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 44%r{ ^\s*(?: <!--| <\?| <![A-Z]| <!\[CDATA\[| </?(?:address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul)\b| <(?:script|pre|style|textarea)\b| </(?:script|pre|style|textarea)\b| </?[A-Za-z][A-Za-z0-9-]*(?:\s+[A-Za-z_:][\w:.-]*(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'=<>`]+))?)*\s*/?>\s*$ ) }mx.freeze
-
HTML_BLOCK_TAGS =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 56%w[ address article aside base basefont blockquote body caption center col colgroup dd details dialog dir div dl dt fieldset figcaption figure footer form frame frameset h1 h2 h3 h4 h5 h6 head header hr html iframe legend li link main menu menuitem nav noframes ol optgroup option p param search section summary table tbody td tfoot th thead title tr track ul ].freeze
-
HTML_TAG_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 63%r{ <!--(?:>|->)| <!--(?:.*?)-->| <\?.*?\?>| <![A-Z][^>]*>| <!\[CDATA\[.*?\]\]>| </[A-Za-z][A-Za-z0-9-]*\s*>| <[A-Za-z][A-Za-z0-9-]* (?:\s+[A-Za-z_:][\w:.-]* (?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'=<>`]+))? )* \s*/?> }mx.freeze
-
LABEL_LIST_BRACKET_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 41/^\s*\[([^\]]+)\](?:[ \t]+(.+))?\s*$/.freeze
-
LABEL_LIST_COLON_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 42/^\s*([^\s:][^:]*)::(?:[ \t]+(.*))?\s*$/.freeze
-
NAMED_ENTITIES =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 17{ 'nbsp' => [0x00A0].pack('U'), 'copy' => [0x00A9].pack('U'), 'AElig' => [0x00C6].pack('U'), 'Dcaron' => [0x010E].pack('U'), 'frac34' => [0x00BE].pack('U'), 'HilbertSpace' => [0x210B].pack('U'), 'DifferentialD' => [0x2146].pack('U'), 'ClockwiseContourIntegral' => [0x2232].pack('U'), 'ngE' => [0x2267, 0x0338].pack('U*'), 'ouml' => [0x00F6].pack('U'), 'quot' => '"', 'amp' => '&' }.freeze -
ORDERED_LIST_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 39/^\s{0,3}(\d+)([.)])[ \t]+(.+?)\s*$/.freeze
-
PLACEHOLDER_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 80/\0(\d+)\0/.freeze
-
RDOC_ESCAPED_CAPITALIZED_CROSSREF_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 82/\\((?:::)?(?:[A-Z]\w+|[A-Z]\w*::\w+)(?:::\w+)*)/.freeze
-
RDOC_HEADING_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 33/^\s*(=+)[ \t]+(.+?)\s*$/.freeze
-
RDOC_ORDERED_LIST_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 40/^\s{0,3}([A-Za-z])\.[ \t]+(.+?)\s*$/.freeze
-
REFERENCE_DEF_START_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 79/^\s{0,3}\[([^\]]+)\]:\s*(.*)$/.freeze
-
SETEXT_HEADING_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 34/^\s{0,3}(=+|-+)\s*$/.freeze
-
TABLE_SEPARATOR_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 37/^\s*\|?(?:\s*:?-+:?\s*\|)+(?:\s*:?-+:?\s*)\|?\s*$/.freeze
-
TAB_WIDTH =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 844 -
THEMATIC_BREAK_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 36/^\s{0,3}(?:(?:-\s*){3,}|(?:\*\s*){3,}|(?:_\s*){3,})\s*$/.freeze
-
UNORDERED_LIST_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 38/^\s{0,3}([*+-])[ \t]+(.+?)\s*$/.freeze
-
YARD_LINK_RE =
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 77/(?<!\\)\{(?!\})(\S+?)(?:\s([^\}]*?\S))?\}(?=\W|.+<\/|$)/m.freeze
Class Method Summary
- .new(text, options = {}) ⇒ HybridMarkdown constructor
Instance Attribute Summary
- #from_path rw
Instance Method Summary
- #to_html ⇒ String
- #append_folded_codepoint(buffer, codepoint) private
- #ascii_only_compat?(text) ⇒ Boolean private
- #ascii_punctuation_char?(char) ⇒ Boolean private
- #autolink_urls(text) private
- #available_delimiter_length(token) private
- #blank_line?(line) ⇒ Boolean private
- #block_boundary?(line) ⇒ Boolean private
- #blockquote_open_fence?(quoted_lines) ⇒ Boolean private
- #blockquote_paragraph_context?(quoted_lines) ⇒ Boolean private
- #blockquote_start?(line) ⇒ Boolean private
- #code_block(text, lang = nil) private
- #colon_indented_code_block_start?(lines, index) ⇒ Boolean private
- #consume_columns(text, columns, start_column = 0, normalize_remaining = false) private
- #contains_nested_link?(label, placeholders) ⇒ Boolean private
- #decode_entities(text) private
- #decode_entity(entity) private
- #delimiter_flags(text, run_start, run_end, char) private
- #each_char_compat(text) private
- #escape_autolink_url(url) private
- #escape_list_marker_text(line) private
- #escape_url(url) private
- #extract_codeblock_language(text, lang = nil) private
- #extract_reference_definitions(text) private
- #fence_closer?(line, char, min_length) ⇒ Boolean private
- #fenced_code_start?(line) ⇒ Boolean private
- #find_braced_text_link_label_end(text, index) private
- #find_closing_bracket(text, open_index) private
- #find_matching_backtick_run(text, index, length) private
- #find_reference_label_end(text) private
- #format_emphasis(text) private
- #format_inline(text) private
- #format_strikethrough(text) private
- #h(text) private
- #heading_id(text) private
- #html_block_end?(type, line) ⇒ Boolean private
- #html_block_start?(line, interrupt_paragraph = false) ⇒ Boolean private
- #html_block_type(line, interrupt_paragraph = false) private
- #image_html(label, dest, title = nil) private
- #indented_code_block_start?(lines, index, previous_block_type = nil) ⇒ Boolean private
- #indented_code_start?(line) ⇒ Boolean private
- #indented_to?(line, indent) ⇒ Boolean private
- #inside_angle_autolink_candidate?(text, index) ⇒ Boolean private
- #labeled_list_start?(lines, index) ⇒ Boolean private
- #lazy_blockquote_continuation?(quoted_lines, line) ⇒ Boolean private
- #leading_columns(line) private
- #link_html(label, dest, title = nil) private
- #list_item_padding(marker) private
- #list_start?(line, interrupt_paragraph = false) ⇒ Boolean private
- #loose_list_item_continuation?(item_lines) ⇒ Boolean private
- #normalize_code_span(code) private
- #normalize_heading_line(line) private
- #normalize_paragraph_line(line) private
- #normalize_reference_label(label) private
- #odd_match_disallowed?(opener, closer) ⇒ Boolean private
- #open_fence_in_lines?(lines) ⇒ Boolean private
- #parse_atx_heading(line) private
- #parse_blockquote(lines, index) private
- #parse_blocks(lines, index) private
- #parse_fence_opener(line) private
- #parse_fenced_code(lines, index) private
- #parse_heading(line) private
- #parse_html_block(lines, index) private
- #parse_indented_code(lines, index) private
- #parse_inline_destination(text, index, placeholders = nil) private
- #parse_labeled_list(lines, index) private
- #parse_labeled_list_line(line) private
- #parse_list(lines, index) private
- #parse_list_marker(line) private
- #parse_paragraph(lines, index) private
- #parse_reference_definition(label, definition) private
- #parse_reference_definition_block(lines, index, previous_line) private
- #parse_setext_heading(lines, index) private
- #parse_table(lines, index) private
- #parse_text_link_destination(text, index) private
- #parse_yard_indented_code(lines, index) private
- #percent_encode_url(text, allowed_re) private
- #plain_text(text) private
- #protect_autolinks(text, placeholders) private
- #protect_braced_text_links(text, placeholders) private
- #protect_code_spans(text, placeholders) private
- #protect_entities(text, placeholders) private
- #protect_escaped_characters(text, placeholders) private
- #protect_hard_breaks(text, placeholders) private
- #protect_inline_images(text, placeholders) private
- #protect_inline_links(text, placeholders) private
- #protect_raw_html(text, placeholders) private
- #protect_rdoc_images(text, placeholders) private
- #protect_reference_images(text, placeholders) private
- #protect_reference_links(text, placeholders) private
- #protect_single_word_text_links(text, placeholders) private
- #protect_yard_links(text, placeholders) private
- #punctuation_char?(char) ⇒ Boolean private
- #reference_definition_context?(previous_line) ⇒ Boolean private
- #reference_definition_continuation?(line) ⇒ Boolean private
- #reference_definition_replacement_line(line, prefix) private
- #reference_image_html(alt, ref) private
- #reference_link_html(label, ref) private
- #replace_inline_constructs(text, placeholders, prefix) private
- #restore_placeholders(text, placeholders) private
- #same_list_type?(base, other) ⇒ Boolean private
- #scan_leading_columns(text) private
- #scan_padding_columns(text, index, start_column) private
- #scan_reference_constructs(text, placeholders, kind) private
- #setext_underline_line?(line) ⇒ Boolean private
- #split_blockquote_prefix(line) private
- #split_lines(text) private
- #split_reference_container_prefix(line) private
- #split_table_row(line) private
- #store_placeholder(placeholders, html) private
- #strip_blockquote_marker(line) private
- #strip_fenced_indent(line, indent) private
- #strip_list_item_indent(line, content_indent) private
- #strip_trailing_punctuation(url) private
- #table_alignment(cell) private
- #table_row?(line) ⇒ Boolean private
- #table_start?(lines, index) ⇒ Boolean private
- #thematic_break?(line) ⇒ Boolean private
- #unclosed_reference_title?(text) ⇒ Boolean private
- #unescape_markdown_punctuation(text) private
- #unicode_casefold_compat(text) private
- #unicode_symbol_char?(char) ⇒ Boolean private
- #unindent(lines) private
- #unindent_indented_code(lines) private
- #utf8_bytes(char) private
- #whitespace_char?(char) ⇒ Boolean private
- #yard_indented_code_start?(lines, index) ⇒ Boolean private
Constructor Details
.new(text, options = {}) ⇒ HybridMarkdown
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 89
def initialize(text, = {}) @heading_ids = .fetch(:heading_ids, true) @references = {} @text = extract_reference_definitions(text.to_s.gsub(/\r\n?/, "\n")) end
Instance Attribute Details
#from_path (rw)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 15
attr_accessor :from_path
Instance Method Details
#append_folded_codepoint(buffer, codepoint) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2123
def append_folded_codepoint(buffer, codepoint) case codepoint when 0x41..0x5A buffer << [codepoint + 32].pack('U') when 0x0391..0x03A1 buffer << [codepoint + 32].pack('U') when 0x03A3..0x03AB buffer << [codepoint + 32].pack('U') when 0x03C2 buffer << [0x03C3].pack('U') when 0x00DF, 0x1E9E buffer << 'ss' else begin buffer << [codepoint].pack('U').downcase rescue StandardError buffer << [codepoint].pack('U') end end end
#ascii_only_compat?(text) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2096
def ascii_only_compat?(text) if text.respond_to?(:ascii_only?) text.ascii_only? else text.to_s.unpack('C*').all? { |byte| byte < 128 } end end
#ascii_punctuation_char?(char) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1617
def ascii_punctuation_char?(char) return false unless ascii_only_compat?(char) byte = char.to_s.unpack('C').first return false unless byte (0x21..0x2F).include?(byte) || (0x3A..0x40).include?(byte) || (0x5B..0x60).include?(byte) || (0x7B..0x7E).include?(byte) end
#autolink_urls(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 814
def autolink_urls(text) text.gsub(/(^|[^\w\/{"'=])((?:https?:\/\/|mailto:)[^\s<]+)/) do match = Regexp.last_match prefix = $1 before_url = text[0...match.begin(2)] if before_url.end_with?('<') || before_url.end_with?('< ') match[0] else url, trailer = strip_trailing_punctuation($2) %(#{prefix}<a href="#{h(url)}">#{h(url)}</a>#{h(trailer)}) end end end
#available_delimiter_length(token) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1559
def available_delimiter_length(token) token[:length] - token[:left_consumed] - token[:right_consumed] end
#blank_line?(line) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 908
def blank_line?(line) line.strip.empty? end
#block_boundary?(line) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1151
def block_boundary?(line) thematic_break?(line) || parse_heading(line) || fenced_code_start?(line) || table_row?(line) || labeled_list_start?([line, ''], 0) || blockquote_start?(line) || html_block_start?(line) || parse_list_marker(line) end
#blockquote_open_fence?(quoted_lines) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2008
def blockquote_open_fence?(quoted_lines) opener = nil quoted_lines.each do |quoted| next if blank_line?(quoted) if opener opener = nil if fence_closer?(quoted, opener[:char], opener[:length]) else opener = parse_fence_opener(quoted) end end !opener.nil? end
#blockquote_paragraph_context?(quoted_lines) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2024
def blockquote_paragraph_context?(quoted_lines) last_content = quoted_lines.reverse.find { |quoted| !blank_line?(quoted) } return false unless last_content return false if fenced_code_start?(last_content) return false if parse_heading(last_content) return false if thematic_break?(last_content) true end
#blockquote_start?(line) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 973
def blockquote_start?(line) !strip_blockquote_marker(line).nil? end
#code_block(text, lang = nil) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1016
def code_block(text, lang = nil) lang, text = extract_codeblock_language(text, lang) attrs = lang ? %( class="#{h(lang)}") : '' "<pre><code#{attrs}>#{h(text)}</code></pre>" end
#colon_indented_code_block_start?(lines, index) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 939
def colon_indented_code_block_start?(lines, index) return false if index.zero? return false unless leading_columns(lines[index]) >= 2 return false if leading_columns(lines[index]) >= 4 previous_line = lines[index - 1] return false if blank_line?(previous_line) previous_line.rstrip.end_with?(':') end
#consume_columns(text, columns, start_column = 0, normalize_remaining = false) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1944
def consume_columns(text, columns, start_column = 0, normalize_remaining = false) index = 0 column = start_column remaining = columns prefix_width = 0 source = text.to_s while index < source.length && remaining > 0 char = source[index, 1] if char == ' ' column += 1 remaining -= 1 index += 1 elsif char == "\t" advance = TAB_WIDTH - (column % TAB_WIDTH) if advance <= remaining column += advance remaining -= advance index += 1 else prefix_width += advance - remaining if normalize_remaining column += advance remaining = 0 index += 1 end else break end end if normalize_remaining while index < source.length char = source[index, 1] if char == ' ' prefix_width += 1 column += 1 index += 1 elsif char == "\t" advance = TAB_WIDTH - (column % TAB_WIDTH) prefix_width += advance column += advance index += 1 else break end end (' ' * prefix_width) + source[index..-1].to_s else source[index..-1].to_s end end
#contains_nested_link?(label, placeholders) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1778
def contains_nested_link?(label, placeholders) text = restore_placeholders(label.to_s, placeholders) return true if text.include?('<a ') index = 0 while index < text.length if text[index, 2] == '![' && (index.zero? || text[index - 1, 1] != '\\') label_open = index + 1 elsif text[index, 1] == '[' && (index.zero? || text[index - 1, 1] != '\\') label_open = index else index += 1 next end label_close = find_closing_bracket(text, label_open) if label_close next_char = text[label_close + 1, 1] return true if next_char == '(' || next_char == '[' end index += 1 end false end
#decode_entities(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1536
def decode_entities(text) text.gsub(ENTITY_RE) do |entity| decode_entity(entity) end end
#decode_entity(entity) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1870
def decode_entity(entity) case entity when /\A&#(\d+);\z/ codepoint = $1.to_i when /\A&#[xX]([0-9A-Fa-f]+);\z/ codepoint = $1.to_i(16) else name = entity[1..-2] return [0x00E4].pack('U') if name == 'auml' return NAMED_ENTITIES[name] || CGI.unescapeHTML(entity) end return [0xFFFD].pack('U') if codepoint.zero? return entity if codepoint > 0x10FFFF [codepoint].pack('U') rescue RangeError entity end
#delimiter_flags(text, run_start, run_end, char) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1572
def delimiter_flags(text, run_start, run_end, char) before = run_start.zero? ? nil : text[run_start - 1, 1] after = run_end >= text.length ? nil : text[run_end, 1] before_whitespace = whitespace_char?(before) after_whitespace = whitespace_char?(after) before_punctuation = punctuation_char?(before) after_punctuation = punctuation_char?(after) left_flanking = !after_whitespace && (!after_punctuation || before_whitespace || before_punctuation) right_flanking = !before_whitespace && (!before_punctuation || after_whitespace || after_punctuation) if char == '_' [ left_flanking && (!right_flanking || before_punctuation), right_flanking && (!left_flanking || after_punctuation) ] else [left_flanking, right_flanking] end end
#each_char_compat(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2088
def each_char_compat(text) if text.respond_to?(:each_char) text.each_char { |char| yield char } else text.scan(/./m) { |char| yield char } end end
#escape_autolink_url(url) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1660
def escape_autolink_url(url) percent_encode_url(url.to_s, /[A-Za-z0-9\-._~:\/?#@!$&'()*+,;=%]/) end
#escape_list_marker_text(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1641
def escape_list_marker_text(line) source = line.to_s.sub(/\n\z/, '') newline = source.length == line.to_s.length ? '' : "\n" if source =~ /\A([*+-])([ \t].*)\z/ "\\#{$1}#{$2}#{newline}" elsif source =~ /\A(\d{1,9}[.)])([ \t].*)\z/ "\\#{$1}#{$2}#{newline}" elsif source =~ /\A([A-Za-z]\.)([ \t].*)\z/ "\\#{$1}#{$2}#{newline}" else source + newline end end
#escape_url(url) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1656
def escape_url(url) percent_encode_url(url.to_s, /[A-Za-z0-9\-._~:\/?#\[\]@!$&'()*+,;=%]/) end
#extract_codeblock_language(text, lang = nil) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1022
def extract_codeblock_language(text, lang = nil) return [lang, text] unless text =~ CODE_LANG_RE lang ||= unescape_markdown_punctuation(decode_entities($1)) [lang, $'] end
#extract_reference_definitions(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 843
def extract_reference_definitions(text) lines = split_lines(text) kept_lines = [] index = 0 in_fenced_code = false previous_line = nil while index < lines.length line = lines[index] if fenced_code_start?(line) in_fenced_code = !in_fenced_code kept_lines << line index += 1 previous_line = line next end if in_fenced_code kept_lines << line index += 1 previous_line = line next end parsed = parse_reference_definition_block(lines, index, previous_line) if parsed normalized = normalize_reference_label(parsed[:label]) @references[normalized] ||= parsed[:reference] unless normalized.empty? kept_lines.concat(parsed[:replacement_lines]) index = parsed[:next_index] previous_line = kept_lines.last next end kept_lines << line index += 1 previous_line = line end kept_lines.join end
#fence_closer?(line, char, min_length) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1071
def fence_closer?(line, char, min_length) stripped = line.sub(/^\s{0,3}/, '') return false unless stripped.start_with?(char) run = stripped[/\A#{Regexp.escape(char)}+/] run && run.length >= min_length && stripped.sub(/\A#{Regexp.escape(run)}/, '').strip.empty? end
#fenced_code_start?(line) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 920
def fenced_code_start?(line) !!parse_fence_opener(line) end
#find_braced_text_link_label_end(text, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1502
def find_braced_text_link_label_end(text, index) cursor = index + 1 while cursor < text.length char = text[cursor, 1] if char == '\\' cursor += 2 next end return cursor if char == '}' cursor += 1 end nil end
#find_closing_bracket(text, open_index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1336
def find_closing_bracket(text, open_index) depth = 0 index = open_index while index < text.length char = text[index, 1] if char == '[' depth += 1 elsif char == ']' depth -= 1 return index if depth.zero? elsif char == '\\' index += 1 end index += 1 end nil end
#find_matching_backtick_run(text, index, length) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1354
def find_matching_backtick_run(text, index, length) while index < text.length if text[index, 1] == '`' run_length = 1 run_length += 1 while index + run_length < text.length && text[index + run_length, 1] == '`' return index if run_length == length index += run_length next end index += 1 end nil end
#find_reference_label_end(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1759
def find_reference_label_end(text) return nil unless text.start_with?('[') index = 1 while index < text.length char = text[index, 1] if char == '\\' index += 2 next end return nil if char == '[' return index if char == ']' && text[index + 1, 1] == ':' index += 1 end nil end
#format_emphasis(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 743
def format_emphasis(text) delimiters = [] output = [] index = 0 while index < text.length char = text[index, 1] if char == '*' || char == '_' run_end = index run_end += 1 while run_end < text.length && text[run_end, 1] == char run_length = run_end - index can_open, can_close = delimiter_flags(text, index, run_end, char) token = { :char => char, :length => run_length, :position => output.length, :left_consumed => 0, :right_consumed => 0, :opening_html => String.new, :closing_html => String.new, :can_open => can_open, :can_close => can_close } output << token if can_close delimiter_index = delimiters.length - 1 while delimiter_index >= 0 && available_delimiter_length(token) > 0 opener = delimiters[delimiter_index] if opener[:char] == char && available_delimiter_length(opener) > 0 && !odd_match_disallowed?(opener, token) use = available_delimiter_length(opener) >= 2 && available_delimiter_length(token) >= 2 ? 2 : 1 opener[:right_consumed] += use opener[:opening_html] = (use == 2 ? '<strong>' : '<em>') + opener[:opening_html] token[:left_consumed] += use token[:closing_html] << (use == 2 ? '</strong>' : '</em>') delimiters.reject! do |candidate| candidate[:position] > opener[:position] && candidate[:position] < token[:position] && available_delimiter_length(candidate) > 0 end delimiters.delete_at(delimiter_index) if available_delimiter_length(opener).zero? delimiter_index = delimiters.length - 1 else delimiter_index -= 1 end end end delimiters << token if can_open && available_delimiter_length(token) > 0 index = run_end else output << char index += 1 end end output.map do |piece| next piece if piece.is_a?(String) piece[:closing_html] + (piece[:char] * available_delimiter_length(piece)) + piece[:opening_html] end.join end
#format_inline(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 525
def format_inline(text) placeholders = [] text = protect_yard_links(text, placeholders) text = protect_raw_html(text, placeholders) text = protect_code_spans(text, placeholders) text = protect_autolinks(text, placeholders) text = protect_hard_breaks(text, placeholders) text = protect_rdoc_images(text, placeholders) text = protect_inline_images(text, placeholders) text = protect_inline_links(text, placeholders) text = protect_braced_text_links(text, placeholders) text = protect_single_word_text_links(text, placeholders) text = protect_reference_images(text, placeholders) text = protect_reference_links(text, placeholders) text = protect_escaped_characters(text, placeholders) text = protect_entities(text, placeholders) text = text.gsub(/[ \t]+\n/, "\n") text = h(text) text = format_emphasis(text) text = format_strikethrough(text) restore_placeholders(autolink_urls(text), placeholders) end
#format_strikethrough(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 810
def format_strikethrough(text) text.gsub(/~~([^\n~](?:.*?[^\n~])?)~~/, '<del>\1</del>') end
#h(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1889
def h(text) text.to_s.gsub('&', '&').gsub('<', '<').gsub('>', '>').gsub('"', '"') end
#heading_id(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1038
def heading_id(text) return '' unless @heading_ids " id=\"#{text.gsub(/\W/, '_')}\"" end
#html_block_end?(type, line) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1851
def html_block_end?(type, line) case type when 1 line =~ %r{</(?:script|pre|style|textarea)\s*>}i when 2 line.include?('-->') when 3 line.include?('?>') when 4 line.include?('>') when 5 line.include?(']]>') when 6, 7 blank_line?(line) else false end end
#html_block_start?(line, interrupt_paragraph = false) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 977
def html_block_start?(line, interrupt_paragraph = false) !html_block_type(line, interrupt_paragraph).nil? end
#html_block_type(line, interrupt_paragraph = false) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1834
def html_block_type(line, interrupt_paragraph = false) stripped = line.chomp return nil unless stripped =~ /^\s{0,3}</ || stripped =~ /^\s{0,3}<(?!!--)/ return 1 if stripped =~ /^\s{0,3}<(?:script|pre|style|textarea)(?:\s|>|$)/i return 2 if stripped =~ /^\s{0,3}<!--/ return 3 if stripped =~ /^\s{0,3}<\?/ return 4 if stripped =~ /^\s{0,3}<![A-Z]/ return 5 if stripped =~ /^\s{0,3}<!\[CDATA\[/ return 6 if stripped =~ /^\s{0,3}<\/?(?:#{HTML_BLOCK_TAGS.join('|')})(?:\s|\/?>|$)/i return nil if interrupt_paragraph return 7 if stripped =~ /^\s{0,3}(?:<[A-Za-z][A-Za-z0-9-]*(?:\s+[A-Za-z_:][\w:.-]*(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'=<>`]+))?)*\s*\/?>|<\/[A-Za-z][A-Za-z0-9-]*\s*>)\s*$/ nil end
#image_html(label, dest, title = nil) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1528
def image_html(label, dest, title = nil) src = escape_url(unescape_markdown_punctuation(decode_entities(dest.to_s))) normalized_title = title && unescape_markdown_punctuation(decode_entities(title)) attrs = %( src="#{h(src)}" alt="#{h(plain_text(label))}") attrs += %( title="#{h(normalized_title)}") if normalized_title "<img#{attrs} />" end
#indented_code_block_start?(lines, index, previous_block_type = nil) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 928
def indented_code_block_start?(lines, index, previous_block_type = nil) return false unless indented_code_start?(lines[index]) return true if leading_columns(lines[index]) >= 4 return true if colon_indented_code_block_start?(lines, index) return false if previous_block_type == :list return false if html_block_start?(lines[index]) return false if parse_setext_heading(lines, index) !index.zero? && blank_line?(lines[index - 1]) end
#indented_code_start?(line) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 924
def indented_code_start?(line) leading_columns(line) >= 2 end
#indented_to?(line, indent) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1633
def indented_to?(line, indent) leading_columns(line) >= indent end
#inside_angle_autolink_candidate?(text, index) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 579
def inside_angle_autolink_candidate?(text, index) opening = text.rindex('<', index) return false unless opening closing = text.rindex('>', index) return false if closing && closing > opening candidate = text[opening...index] return false if candidate =~ /\s/ candidate =~ /\A<(?:[A-Za-z][A-Za-z0-9.+-]{1,31}:|[A-Za-z0-9.!#$%&'*+\/=?^_`{|}~-]+@)/ end
#labeled_list_start?(lines, index) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 967
def labeled_list_start?(lines, index) line = lines[index] return true if line =~ LABEL_LIST_COLON_RE false end
#lazy_blockquote_continuation?(quoted_lines, line) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1997
def lazy_blockquote_continuation?(quoted_lines, line) return false if block_boundary?(line) return false if indented_code_start?(line) && !blockquote_paragraph_context?(quoted_lines) last_content = quoted_lines.reverse.find { |quoted| !blank_line?(quoted) } return false if last_content && fenced_code_start?(last_content) return false if last_content && indented_code_start?(last_content) true end
#leading_columns(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1629
def leading_columns(line) scan_leading_columns(line.to_s).first end
#link_html(label, dest, title = nil) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1520
def link_html(label, dest, title = nil) href = escape_url(unescape_markdown_punctuation(decode_entities(dest.to_s))) normalized_title = title && unescape_markdown_punctuation(decode_entities(title)) attrs = %( href="#{h(href)}") attrs += %( title="#{h(normalized_title)}") if normalized_title %(<a#{attrs}>#{format_inline(label)}</a>) end
#list_item_padding(marker) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1140
def list_item_padding(marker) (1..4).include?(marker[:padding]) ? marker[:padding] : 1 end
#list_start?(line, interrupt_paragraph = false) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 958
def list_start?(line, interrupt_paragraph = false) return false unless (marker = parse_list_marker(line)) return true unless interrupt_paragraph return false if marker[:content].empty? !marker[:ordered] || marker[:start] == 1 end
#loose_list_item_continuation?(item_lines) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2063
def loose_list_item_continuation?(item_lines) return false if open_fence_in_lines?(item_lines) previous = item_lines.reverse.find { |item_line| item_line != "\n" } return true unless previous !parse_list_marker(previous.chomp) end
#normalize_code_span(code) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1550
def normalize_code_span(code) code = code.gsub(/\n/, ' ') if code.length > 1 && code.start_with?(' ') && code.end_with?(' ') && code.strip != '' code[1...-1] else code end end
#normalize_heading_line(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2038
def normalize_heading_line(line) normalize_paragraph_line(line).rstrip end
#normalize_paragraph_line(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2034
def normalize_paragraph_line(line) line.to_s.chomp.sub(/^\s+/, '') end
#normalize_reference_label(label) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 885
def normalize_reference_label(label) normalized = label.to_s.gsub(/\\([\[\]])/, '\1').gsub(/\s+/, ' ').strip unicode_casefold_compat(normalized) end
#odd_match_disallowed?(opener, closer) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1563
def odd_match_disallowed?(opener, closer) return false unless opener[:can_close] || closer[:can_open] opener_len = available_delimiter_length(opener) closer_len = available_delimiter_length(closer) ((opener_len + closer_len) % 3).zero? && (opener_len % 3 != 0 || closer_len % 3 != 0) end
#open_fence_in_lines?(lines) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2072
def open_fence_in_lines?(lines) opener = nil lines.each do |line| next if blank_line?(line) if opener opener = nil if fence_closer?(line, opener[:char], opener[:length]) else opener = parse_fence_opener(line) end end !opener.nil? end
#parse_atx_heading(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1044
def parse_atx_heading(line) stripped = line.chomp.sub(/^\s{0,3}/, '') match = stripped.match(/\A(#{'#' * 6}|#{'#' * 5}|#{'#' * 4}|#{'#' * 3}|#{'#' * 2}|#)(?=[ \t]|$)(.*)\z/) return nil unless match level = match[1].length content = match[2] content = content.sub(/\A[ \t]+/, '') content = content.sub(/[ \t]+#+[ \t]*\z/, '') content = '' if content =~ /\A#+\z/ content = content.rstrip "<h#{level}#{heading_id(content)}>#{format_inline(content)}</h#{level}>" end
#parse_blockquote(lines, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 443
def parse_blockquote(lines, index) quoted_lines = [] saw_quote = false previous_blank = false while index < lines.length line = lines[index] break if saw_quote && quoted_lines.last == "\n" && !blockquote_start?(line) break if saw_quote && blank_line?(line) && blockquote_open_fence?(quoted_lines) break if saw_quote && previous_blank break if saw_quote && !blank_line?(line) && !blockquote_start?(line) && !lazy_blockquote_continuation?(quoted_lines, line) break unless blank_line?(line) || blockquote_start?(line) || saw_quote if blank_line?(line) quoted_lines << "\n" previous_blank = true elsif (stripped = strip_blockquote_marker(line)) quoted_lines << stripped saw_quote = true previous_blank = false else if setext_underline_line?(line) quoted_lines << " #{line.lstrip}" else quoted_lines << line end previous_blank = false end index += 1 end inner_html = parse_blocks(quoted_lines, 0).join("\n") [inner_html.empty? ? "<blockquote>\n</blockquote>" : "<blockquote>\n#{inner_html}\n</blockquote>", index] end
#parse_blocks(lines, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 102
def parse_blocks(lines, index) blocks = [] previous_block_type = nil while index < lines.length line = lines[index] if blank_line?(line) index += 1 elsif yard_indented_code_start?(lines, index) block, index = parse_yard_indented_code(lines, index) blocks << block previous_block_type = :code elsif indented_code_block_start?(lines, index, previous_block_type) block, index = parse_indented_code(lines, index) blocks << block previous_block_type = :code elsif thematic_break?(line) blocks << '<hr />' index += 1 previous_block_type = :hr elsif (heading = parse_setext_heading(lines, index)) blocks << heading[0] index = heading[1] previous_block_type = :heading elsif (heading = parse_heading(line)) blocks << heading index += 1 previous_block_type = :heading elsif fenced_code_start?(line) block, index = parse_fenced_code(lines, index) blocks << block previous_block_type = :code elsif table_start?(lines, index) block, index = parse_table(lines, index) blocks << block previous_block_type = :table elsif labeled_list_start?(lines, index) block, index = parse_labeled_list(lines, index) blocks << block previous_block_type = :list elsif blockquote_start?(line) block, index = parse_blockquote(lines, index) blocks << block previous_block_type = :blockquote elsif list_start?(line) block, index = parse_list(lines, index) blocks << block previous_block_type = :list elsif html_block_start?(line) block, index = parse_html_block(lines, index) blocks << block previous_block_type = :html else block, index = parse_paragraph(lines, index) blocks << block unless block.empty? previous_block_type = :paragraph unless block.empty? end end blocks end
#parse_fence_opener(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1058
def parse_fence_opener(line) match = line.match(FENCE_RE) return nil unless match indent = match[1].length fence = match[2] info = match[3].to_s.strip return nil if fence.start_with?('`') && info.include?('`') lang = info.empty? ? nil : unescape_markdown_punctuation(decode_entities(info.split(/[ \t]/, 2).first)) {:char => fence[0, 1], :length => fence.length, :indent => indent, :lang => lang} end
#parse_fenced_code(lines, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 216
def parse_fenced_code(lines, index) opener = parse_fence_opener(lines[index]) fence_char = opener[:char] fence_length = opener[:length] indent = opener[:indent] lang = opener[:lang] index += 1 body = [] while index < lines.length break if fence_closer?(lines[index], fence_char, fence_length) body << strip_fenced_indent(lines[index], indent) index += 1 end index += 1 if index < lines.length [code_block(body.join, lang), index] end
#parse_heading(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 165
def parse_heading(line) if (heading = parse_atx_heading(line)) return heading end match = RDOC_HEADING_RE.match(line) return unless match heading_marks = match[1] heading_text = match[2].strip return nil if heading_text =~ /\A[=\-]+\z/ level = [heading_marks.length, 6].min "<h#{level}#{heading_id(heading_text)}>#{format_inline(heading_text)}</h#{level}>" end
#parse_html_block(lines, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 479
def parse_html_block(lines, index) html = [] type = html_block_type(lines[index]) return ['', index] unless type while index < lines.length line = lines[index] break if html.any? && [6, 7].include?(type) && html_block_end?(type, line) break unless html.any? || html_block_type(line) html << line.chomp if html_block_end?(type, line) index += 1 break end index += 1 end [html.join("\n"), index] end
#parse_indented_code(lines, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 236
def parse_indented_code(lines, index) body = [] previous_blank = false while index < lines.length line = lines[index] break if previous_blank && html_block_start?(line) break unless blank_line?(line) || indented_code_start?(line) body << line previous_blank = blank_line?(line) index += 1 end body.pop while body.any? && blank_line?(body.last) [code_block(unindent_indented_code(body)), index] end
#parse_inline_destination(text, index, placeholders = nil) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1370
def parse_inline_destination(text, index, placeholders = nil) while index < text.length && text[index, 1] =~ /[ \t\n]/ index += 1 end if text[index, 1] == '<' close = text.index('>', index + 1) return [nil, nil, nil] unless close dest = text[(index + 1)...close] return [nil, nil, nil] if dest.include?("\n") || dest.include?('\\') dest = dest.gsub(' ', '%20') index = close + 1 else close = index parens = 0 while close < text.length char = text[close, 1] if char == '\\' && close + 1 < text.length close += 2 next end break if parens.zero? && (char == ')' || char =~ /\s/) parens += 1 if char == '(' parens -= 1 if char == ')' close += 1 end dest = text[index...close] index = close end if placeholders restored_dest = restore_placeholders(dest.to_s, placeholders) if restored_dest.start_with?('<') return [nil, nil, nil] if restored_dest.include?("\n") || restored_dest.include?('\\') return [nil, nil, nil] unless restored_dest.end_with?('>') && restored_dest.index('>') == restored_dest.length - 1 dest = restored_dest[1...-1] end end while index < text.length && text[index, 1] =~ /[ \t\n]/ index += 1 end title = nil if text[index, 1] == '"' || text[index, 1] == "'" delimiter = text[index, 1] index += 1 buffer = String.new while index < text.length char = text[index, 1] if char == '\\' && index + 1 < text.length buffer << text[index, 2] index += 2 next end break if char == delimiter buffer << char index += 1 end return [nil, nil, nil] unless index < text.length && text[index, 1] == delimiter title = buffer index += 1 elsif text[index, 1] == '(' index += 1 buffer = String.new depth = 1 while index < text.length char = text[index, 1] if char == '\\' && index + 1 < text.length buffer << text[index, 2] index += 2 next end if char == '(' depth += 1 elsif char == ')' depth -= 1 break if depth.zero? end buffer << char index += 1 end return [nil, nil, nil] unless index < text.length && text[index, 1] == ')' title = buffer index += 1 end while index < text.length && text[index, 1] =~ /[ \t\n]/ index += 1 end return [nil, nil, nil] unless text[index, 1] == ')' [dest.to_s, title, index + 1] end
#parse_labeled_list(lines, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 408
def parse_labeled_list(lines, index) items = [] while index < lines.length label, body = parse_labeled_list_line(lines[index]) break unless label index += 1 body_lines = [] body_lines << body if body && !body.empty? while index < lines.length line = lines[index] break if blank_line?(line) break if parse_labeled_list_line(line) break if !line.strip.empty? && !line.match(/^(?: {2,}|\t)/) body_lines << line.sub(/^(?: {2,}|\t)/, '').chomp index += 1 end body_html = if body_lines.empty? '' else parse_blocks(body_lines.map { |l| "#{l}\n" }, 0).join("\n") end items << "<dt>#{format_inline(label)}</dt>\n<dd>#{body_html}</dd>" index += 1 while index < lines.length && blank_line?(lines[index]) end ["<dl>\n#{items.join("\n")}\n</dl>", index] end
#parse_labeled_list_line(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 837
def parse_labeled_list_line(line) return [$1, $2] if line =~ LABEL_LIST_COLON_RE nil end
#parse_list(lines, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 296
def parse_list(lines, index) marker = parse_list_marker(lines[index]) ordered = marker[:ordered] tag = ordered ? 'ol' : 'ul' start_attr = ordered && marker[:start] != 1 ? %( start="#{marker[:start]}") : '' items = [] tight = true list_indent = marker[:indent] while index < lines.length break if items.any? && thematic_break?(lines[index]) && leading_columns(lines[index]) <= list_indent + 3 item_marker = parse_list_marker(lines[index]) break unless item_marker && same_list_type?(marker, item_marker) effective_padding = list_item_padding(item_marker) content_indent = item_marker[:indent] + item_marker[:marker_length] + effective_padding lazy_indent = item_marker[:indent] + effective_padding item_lines = [] first_line = item_marker[:content] unless first_line.empty? leading = [item_marker[:padding] - effective_padding, 0].max item_lines << "#{' ' * leading}#{first_line}\n" end index += 1 blank_seen = false item_loose = false while index < lines.length line = lines[index] break if thematic_break?(line) && !indented_to?(line, content_indent) break if setext_underline_line?(line) && !indented_to?(line, content_indent) next_marker = parse_list_marker(line) if next_marker && same_list_type?(marker, next_marker) && (next_marker[:indent] == item_marker[:indent] || (blank_seen && next_marker[:indent] <= list_indent + 3)) if blank_seen tight = false end break end break if next_marker && next_marker[:indent] < content_indent break if !blank_seen && !indented_to?(line, content_indent) && block_boundary?(line) if blank_line?(line) item_lines << "\n" blank_seen = true elsif blank_seen && indented_to?(line, content_indent) break if first_line.empty? && item_lines.all? { |item_line| item_line == "\n" } && leading_columns(line) == content_indent item_loose = true if loose_list_item_continuation?(item_lines) stripped = strip_list_item_indent(line, content_indent) item_lines << stripped blank_seen = false elsif !blank_seen && indented_to?(line, content_indent) stripped = strip_list_item_indent(line, content_indent) item_lines << stripped blank_seen = false elsif !blank_seen stripped = strip_list_item_indent(line, lazy_indent) stripped = escape_list_marker_text(stripped) if parse_list_marker(stripped) item_lines << stripped blank_seen = false else break end index += 1 end item_blocks = parse_blocks(item_lines, 0) item_html = item_blocks.join("\n") item_html = format_inline(first_line) if item_html.empty? && !first_line.empty? simple_item = !item_loose && item_blocks.length == 1 && item_html =~ /\A<p>(.*?)<\/p>\z/m && item_html !~ /<(?:pre|blockquote|ul|ol|dl|table|h\d|hr)/m if item_html.empty? item_html = '' else item_loose ||= item_blocks.count { |block| block.start_with?('<p>') } > 1 end tight &&= !item_loose items << {:html => item_html, :simple => simple_item} end items.map! do |item| item_html = item[:html] item_html = "<p>#{item_html}</p>" if !tight && !item_html.empty? && item_html !~ /\A</m item_html = item_html.sub(/\A<p>(.*?)<\/p>(?=\n<(?:ul|ol|blockquote|pre|h\d|table|hr))/m, '\1') if tight item_html = item_html.sub(/\n<p>(.*?)<\/p>\z/m, "\n\\1") if tight item_html = item_html.sub(/\A<p>(.*?)<\/p>\z/m, '\1') if item[:simple] && tight if item_html.empty? '<li></li>' elsif item[:simple] && tight "<li>#{item_html}</li>" elsif item_html !~ /\A</m suffix = item_html.include?("\n") ? "\n" : '' "<li>#{item_html}#{suffix}</li>" else suffix = item_html =~ /(?:<\/(?:p|pre|blockquote|ul|ol|dl|table|h\d)>|<hr \/>|<[A-Za-z][A-Za-z0-9-]*>)\z/m ? "\n" : '' "<li>\n#{item_html}#{suffix}</li>" end end ["<#{tag}#{start_attr}>\n#{items.join("\n")}\n</#{tag}>", index] end
#parse_list_marker(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1085
def parse_list_marker(line) source = line.to_s.sub(/\n\z/, '') indent, index = scan_leading_columns(source) return nil if indent > 3 return nil if index >= source.length char = source[index, 1] current_column = indent if '*+-'.include?(char) marker_length = 1 marker_end = index + 1 current_column += 1 padding, marker_end = scan_padding_columns(source, marker_end, current_column) content = source[marker_end..-1].to_s return nil if padding.zero? && !content.empty? return {:ordered => false, :bullet => char, :indent => indent, :marker_length => marker_length, :padding => padding, :content => content} end number = source[index..-1][/^\d{1,9}/] if number marker_end = index + number.length delimiter = source[marker_end, 1] if delimiter == '.' || delimiter == ')' marker_length = number.length + 1 current_column += marker_length marker_end += 1 padding, marker_end = scan_padding_columns(source, marker_end, current_column) content = source[marker_end..-1].to_s return nil if padding.zero? && !content.empty? return {:ordered => true, :delimiter => delimiter, :start => number.to_i, :indent => indent, :marker_length => marker_length, :padding => padding, :content => content} end end if source[index, 2] =~ /\A[A-Za-z]\.\z/ marker_length = 2 marker_end = index + marker_length current_column += marker_length padding, marker_end = scan_padding_columns(source, marker_end, current_column) content = source[marker_end..-1].to_s return nil if padding.zero? && !content.empty? return {:ordered => true, :delimiter => '.', :start => 1, :indent => indent, :marker_length => marker_length, :padding => padding, :content => content} end nil end
#parse_paragraph(lines, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 500
def parse_paragraph(lines, index) buffer = [] while index < lines.length line = lines[index] break if blank_line?(line) break if !buffer.empty? && colon_indented_code_block_start?(lines, index) break if thematic_break?(line) break if parse_setext_heading(lines, index) break if parse_heading(line) break if fenced_code_start?(line) break if table_start?(lines, index) break if labeled_list_start?(lines, index) break if blockquote_start?(line) break if list_start?(line, true) break if html_block_start?(line, true) buffer << line.chomp index += 1 end text = buffer.map { |line| normalize_paragraph_line(line) }.join("\n").strip [text.empty? ? '' : "<p>#{format_inline(text)}</p>", index] end
#parse_reference_definition(label, definition) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1157
def parse_reference_definition(label, definition) definition = definition.to_s return nil if normalize_reference_label(label).empty? index = 0 index += 1 while index < definition.length && definition[index, 1] =~ /[ \t\n]/ return nil if index >= definition.length if definition[index, 1] == '<' close = definition.index('>', index + 1) return nil unless close url = definition[(index + 1)...close] return nil if url.include?("\n") index = close + 1 return nil if index < definition.length && definition[index, 1] !~ /[ \t\n]/ else start = index while index < definition.length && definition[index, 1] !~ /[ \t\n]/ index += 1 end url = definition[start...index] end return nil if url.nil? || url.include?('<') || url.include?('>') index += 1 while index < definition.length && definition[index, 1] =~ /[ \t\n]/ title = nil if index < definition.length delimiter = definition[index, 1] close_delimiter = delimiter == '(' ? ')' : delimiter if delimiter == '"' || delimiter == "'" || delimiter == '(' index += 1 start = index buffer = String.new while index < definition.length char = definition[index, 1] if char == '\\' && index + 1 < definition.length buffer << definition[index, 2] index += 2 next end break if char == close_delimiter buffer << char index += 1 end return nil if index >= definition.length || definition[index, 1] != close_delimiter title = buffer index += 1 index += 1 while index < definition.length && definition[index, 1] =~ /[ \t\n]/ return nil unless index == definition.length else return nil end end { :url => escape_url(unescape_markdown_punctuation(decode_entities(url))), :title => title && unescape_markdown_punctuation(decode_entities(title)) } end
#parse_reference_definition_block(lines, index, previous_line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1664
def parse_reference_definition_block(lines, index, previous_line) line = lines[index] return nil unless reference_definition_context?(previous_line) prefix, content = split_reference_container_prefix(line) return nil unless content =~ /^\s{0,3}\[/ label_buffer = content.sub(/^\s{0,3}/, '') consumed_lines = [line] label_end = find_reference_label_end(label_buffer) current_index = index while label_end.nil? current_index += 1 return nil if current_index >= lines.length next_prefix, next_content = split_reference_container_prefix(lines[current_index]) return nil unless next_prefix == prefix label_buffer << next_content consumed_lines << lines[current_index] label_end = find_reference_label_end(label_buffer) end label = label_buffer[1...label_end] remainder = label_buffer[(label_end + 2)..-1].to_s current_index += 1 while remainder.strip.empty? && current_index < lines.length next_prefix, next_content = split_reference_container_prefix(lines[current_index]) break unless next_prefix == prefix break if blank_line?(next_content) remainder << (remainder.empty? ? next_content : "\n#{next_content}") consumed_lines << lines[current_index] current_index += 1 end while unclosed_reference_title?(remainder) && current_index < lines.length next_prefix, next_content = split_reference_container_prefix(lines[current_index]) break unless next_prefix == prefix break if blank_line?(next_content) remainder << "\n#{next_content}" consumed_lines << lines[current_index] current_index += 1 end while current_index < lines.length next_prefix, next_content = split_reference_container_prefix(lines[current_index]) break unless next_prefix == prefix break unless reference_definition_continuation?(next_content) remainder << "\n#{next_content.strip}" consumed_lines << lines[current_index] current_index += 1 end reference = parse_reference_definition(label, remainder) return nil unless reference { :label => label, :reference => reference, :replacement_lines => consumed_lines.map { |consumed| reference_definition_replacement_line(consumed, prefix) }, :next_index => current_index } end
#parse_setext_heading(lines, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 181
def parse_setext_heading(lines, index) return nil if index + 1 >= lines.length return nil if lines[index].strip.empty? return nil if lines[index] =~ /^\s{0,3}>/ return nil if parse_list_marker(lines[index]) return nil if lines[index] =~ /^(?: {4,}|\t)/ return nil if parse_heading(lines[index]) return nil if fenced_code_start?(lines[index]) content_lines = [] current_index = index while current_index < lines.length line = lines[current_index] return nil if blank_line?(line) if line =~ SETEXT_HEADING_RE return nil if content_lines.empty? level = $1.start_with?('=') ? 1 : 2 text = content_lines.join("\n") return ["<h#{level}#{heading_id(text)}>#{format_inline(text)}</h#{level}>", current_index + 1] end if current_index > index && block_boundary?(line) return nil end content_lines << normalize_heading_line(line) current_index += 1 end nil end
#parse_table(lines, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 267
def parse_table(lines, index) header = split_table_row(lines[index]) alignments = split_table_row(lines[index + 1]).map { |cell| table_alignment(cell) } rows = [] index += 2 while index < lines.length && table_row?(lines[index]) rows << split_table_row(lines[index]) index += 1 end html = "<table>\n<thead>\n<tr>\n".dup header.each_with_index do |cell, i| attrs = alignments[i] ? %( align="#{alignments[i]}") : "" html << "<th#{attrs}>#{format_inline(cell)}</th>\n" end html << "</tr>\n</thead>\n<tbody>\n" rows.each do |row| html << "<tr>\n" row.each_with_index do |cell, i| attrs = alignments[i] ? %( align="#{alignments[i]}") : "" html << "<td#{attrs}>#{format_inline(cell)}</td>\n" end html << "</tr>\n" end html << "</tbody>\n</table>" [html, index] end
#parse_text_link_destination(text, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1473
def parse_text_link_destination(text, index) return [nil, 0] unless text[index, 1] == '[' dest = String.new cursor = index + 1 while cursor < text.length char = text[cursor, 1] if char == '\\' escaped = text[cursor + 1, 1] return [nil, 0] unless escaped && "[]\\*+<_".include?(escaped) dest << escaped cursor += 2 next end return [nil, 0] if char =~ /\s/ return [dest, cursor - index + 1] if char == ']' return [nil, 0] if char == '[' dest << char cursor += 1 end [nil, 0] end
#parse_yard_indented_code(lines, index) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 253
def parse_yard_indented_code(lines, index) body = [] while index < lines.length line = lines[index] break unless blank_line?(line) || indented_code_start?(line) body << line index += 1 end body.pop while body.any? && blank_line?(body.last) [code_block(unindent(body)), index] end
#percent_encode_url(text, allowed_re) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1818
def percent_encode_url(text, allowed_re) encoded = String.new each_char_compat(text.to_s) do |char| if ascii_only_compat?(char) && char =~ /\A#{allowed_re.source}\z/ encoded << char else utf8_bytes(char).each do |byte| encoded << sprintf('%%%02X', byte) end end end encoded end
#plain_text(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1466
def plain_text(text) text = text.to_s.gsub(/!\[([^\]]*)\]\([^)]+\)/, '\1') text = text.gsub(/\[([^\]]+)\]\([^)]+\)/, '\1') text = text.gsub(/[*_~`]/, '') decode_entities(unescape_markdown_punctuation(text)) end
#protect_autolinks(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 603
def protect_autolinks(text, placeholders) text.gsub(AUTOLINK_RE) do href = $1 link_href = href.include?('@') && href !~ /\A[A-Za-z][A-Za-z0-9.+-]{1,31}:/ ? "mailto:#{href}" : escape_autolink_url(href) store_placeholder(placeholders, %(<a href="#{h(link_href)}">#{h(href)}</a>)) end end
#protect_braced_text_links(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 711
def protect_braced_text_links(text, placeholders) output = String.new index = 0 while index < text.length if text[index, 1] == '\\' && index + 1 < text.length output << text[index, 2] index += 2 next end if text[index, 1] == '{' label_end = find_braced_text_link_label_end(text, index) if label_end label = text[(index + 1)...label_end] dest, consumed = parse_text_link_destination(text, label_end + 1) if dest output << store_placeholder(placeholders, link_html(label, dest)) index = label_end + 1 + consumed next end end end output << text[index, 1] index += 1 end output end
#protect_code_spans(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 548
def protect_code_spans(text, placeholders) output = String.new index = 0 while index < text.length if text[index, 1] == '`' && (index.zero? || text[index - 1, 1] != '\\') && !inside_angle_autolink_candidate?(text, index) opener_length = 1 opener_length += 1 while index + opener_length < text.length && text[index + opener_length, 1] == '`' closer_index = find_matching_backtick_run(text, index + opener_length, opener_length) if closer_index code = normalize_code_span(restore_placeholders(text[(index + opener_length)...closer_index], placeholders)) output << store_placeholder(placeholders, "<code>#{h(code)}</code>") index = closer_index + opener_length next end output << ('`' * opener_length) index += opener_length next end output << text[index, 1] index += 1 end output.gsub(/(^|[\s>])\+([^\s+\n](?:[^+\n]*?[^\s+\n])?)\+(?=$|[\s<.,;:!?)]|\z)/) do prefix = $1 prefix + store_placeholder(placeholders, "<code>#{h(restore_placeholders($2, placeholders))}</code>") end end
#protect_entities(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 631
def protect_entities(text, placeholders) text.gsub(ENTITY_RE) { store_placeholder(placeholders, h(decode_entity($&))) } end
#protect_escaped_characters(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 623
def protect_escaped_characters(text, placeholders) text = text.gsub(RDOC_ESCAPED_CAPITALIZED_CROSSREF_RE) do store_placeholder(placeholders, h($1)) end text.gsub(ESCAPABLE_CHARS_RE) { store_placeholder(placeholders, h($1)) } end
#protect_hard_breaks(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 635
def protect_hard_breaks(text, placeholders) text.gsub(/(?:\\|\s{2,})\n/) { store_placeholder(placeholders, "<br />\n") } end
#protect_inline_images(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 647
def protect_inline_images(text, placeholders) replace_inline_constructs(text, placeholders, '!') do |label, dest, title| store_placeholder(placeholders, image_html( restore_placeholders(label, placeholders), restore_placeholders(dest, placeholders), title && restore_placeholders(title, placeholders) )) end end
#protect_inline_links(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 657
def protect_inline_links(text, placeholders) replace_inline_constructs(text, placeholders, nil) do |label, dest, title| store_placeholder(placeholders, link_html( restore_placeholders(label, placeholders), restore_placeholders(dest, placeholders), title && restore_placeholders(title, placeholders) )) end end
#protect_raw_html(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 611
def protect_raw_html(text, placeholders) text.gsub(/(?<!\\)#{HTML_TAG_RE}/m) do match = $& match_start = Regexp.last_match.begin(0) if match_start > 0 && text[match_start - 1, 1] == '`' match else store_placeholder(placeholders, match) end end end
#protect_rdoc_images(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 639
def protect_rdoc_images(text, placeholders) text.gsub(/(^|[ \t\n])rdoc-image:([A-Za-z][A-Za-z0-9+.-]*:\/\/\S+)(?=$|[ \t\n])/) do prefix = Regexp.last_match(1) dest = Regexp.last_match(2) prefix + store_placeholder(placeholders, image_html('', dest)) end end
#protect_reference_images(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 667
def protect_reference_images(text, placeholders) scan_reference_constructs(text, placeholders, :image) end
#protect_reference_links(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 671
def protect_reference_links(text, placeholders) scan_reference_constructs(text, placeholders, :link) end
#protect_single_word_text_links(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 675
def protect_single_word_text_links(text, placeholders) output = String.new index = 0 bracket_depth = 0 while index < text.length char = text[index, 1] if char == '\\' && index + 1 < text.length output << text[index, 2] index += 2 next elsif char == '[' bracket_depth += 1 elsif char == ']' && bracket_depth > 0 bracket_depth -= 1 end if bracket_depth.zero? && (match = text[index..-1].match(/\A([A-Za-z0-9]+)(?=\[)/)) label = match[1] dest, consumed = parse_text_link_destination(text, index + label.length) if dest output << store_placeholder(placeholders, link_html(label, dest)) index += label.length + consumed next end end output << char index += 1 end output end
#protect_yard_links(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 592
def protect_yard_links(text, placeholders) text.gsub(YARD_LINK_RE) do match = Regexp.last_match if text[match.end(0), 1] == '[' match[0] else store_placeholder(placeholders, match[0]) end end end
#punctuation_char?(char) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1597
def punctuation_char?(char) return false if char.nil? ascii_punctuation_char?(char) || unicode_symbol_char?(char) end
#reference_definition_context?(previous_line) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1733
def reference_definition_context?(previous_line) return true if previous_line.nil? return true if blank_line?(previous_line) stripped = split_reference_container_prefix(previous_line).last block_boundary?(stripped) end
#reference_definition_continuation?(line) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1542
def reference_definition_continuation?(line) return true if line =~ /^(?: {1,3}|\t)(.*)$/ return true if line =~ /\A<(?:[^>\n]*)>\s*\z/ return true if line =~ /\A(?:"[^"]*"|'[^']*'|\([^)]*\))\s*\z/ false end
#reference_definition_replacement_line(line, prefix) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1753
def reference_definition_replacement_line(line, prefix) return '' if prefix.empty? prefix.rstrip + "\n" end
#reference_image_html(alt, ref) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 899
def reference_image_html(alt, ref) reference = @references[normalize_reference_label(ref)] return nil unless reference attrs = %( src="#{h(reference[:url])}" alt="#{h(plain_text(alt))}") attrs += %( title="#{h(reference[:title])}") if reference[:title] "<img#{attrs} />" end
#reference_link_html(label, ref) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 890
def reference_link_html(label, ref) reference = @references[normalize_reference_label(ref)] return nil unless reference attrs = %( href="#{h(reference[:url])}") attrs += %( title="#{h(reference[:title])}") if reference[:title] %(<a#{attrs}>#{format_inline(unescape_markdown_punctuation(label))}</a>) end
#replace_inline_constructs(text, placeholders, prefix) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1219
def replace_inline_constructs(text, placeholders, prefix) output = String.new index = 0 while index < text.length if prefix if text[index, 2] != '![' || (index > 0 && text[index - 1, 1] == '\\') output << text[index, 1] index += 1 next end label_start = index + 2 else if text[index, 1] != '[' || (index > 0 && text[index - 1, 1] == '\\') output << text[index, 1] index += 1 next end label_start = index + 1 end label_end = find_closing_bracket(text, label_start - 1) unless label_end && text[label_end + 1, 1] == '(' output << text[index, 1] index += 1 next end dest, title, consumed = parse_inline_destination(text, label_end + 2, placeholders) unless consumed output << text[index, 1] index += 1 next end label = text[label_start...label_end] if !prefix && contains_nested_link?(label, placeholders) output << text[index, 1] index += 1 next end output << yield(label, dest, title) index = consumed end output end
#restore_placeholders(text, placeholders) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 828
def restore_placeholders(text, placeholders) text.gsub(PLACEHOLDER_RE) { placeholders[$1.to_i] } end
#same_list_type?(base, other) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1144
def same_list_type?(base, other) return false unless other return base[:bullet] == other[:bullet] if !base[:ordered] && !other[:ordered] base[:ordered] && other[:ordered] && base[:delimiter] == other[:delimiter] end
#scan_leading_columns(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1901
def scan_leading_columns(text) index = 0 column = 0 source = text.to_s while index < source.length char = source[index, 1] if char == ' ' column += 1 elsif char == "\t" column += TAB_WIDTH - (column % TAB_WIDTH) else break end index += 1 end [column, index] end
#scan_padding_columns(text, index, start_column) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1921
def scan_padding_columns(text, index, start_column) column = start_column padding = 0 source = text.to_s while index < source.length char = source[index, 1] if char == ' ' column += 1 padding += 1 elsif char == "\t" advance = TAB_WIDTH - (column % TAB_WIDTH) column += advance padding += advance else break end index += 1 end [padding, index] end
#scan_reference_constructs(text, placeholders, kind) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1267
def scan_reference_constructs(text, placeholders, kind) output = String.new index = 0 while index < text.length image = kind == :image if image if text[index, 2] != '![' || (index > 0 && text[index - 1, 1] == '\\') output << text[index, 1] index += 1 next end label_open = index + 1 else if text[index, 1] != '[' || (index > 0 && text[index - 1, 1] == '\\') output << text[index, 1] index += 1 next end label_open = index end label_close = find_closing_bracket(text, label_open) unless label_close output << text[index, 1] index += 1 next end next_char = text[label_close + 1, 1] label = restore_placeholders(text[(label_open + 1)...label_close], placeholders) html = nil consumed = nil if next_char == '[' ref_close = find_closing_bracket(text, label_close + 1) if ref_close ref = restore_placeholders(text[(label_close + 2)...ref_close], placeholders) ref = label if ref.empty? if kind == :link && contains_nested_link?(label, placeholders) output << text[index] index += 1 next end html = kind == :image ? reference_image_html(label, ref) : reference_link_html(label, ref) consumed = ref_close + 1 if html end else if kind == :link && contains_nested_link?(label, placeholders) output << text[index, 1] index += 1 next end html = kind == :image ? reference_image_html(label, label) : reference_link_html(label, label) consumed = label_close + 1 if html end if html output << store_placeholder(placeholders, html) index = consumed else output << text[index, 1] index += 1 end end output end
#setext_underline_line?(line) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 916
def setext_underline_line?(line) line =~ SETEXT_HEADING_RE end
#split_blockquote_prefix(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2042
def split_blockquote_prefix(line) source = line.to_s indent, index = scan_leading_columns(source) return nil if indent > 3 return nil unless source[index, 1] == '>' prefix = source[0..index] rest = source[(index + 1)..-1].to_s if rest.start_with?(' ') || rest.start_with?("\t") prefix << rest[0, 1] rest = consume_columns(rest, 1, indent + 1, true) end [prefix, rest.end_with?("\n") ? rest : "#{rest}\n"] end
#split_lines(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1897
def split_lines(text) text.to_s.split(/^/, -1) end
#split_reference_container_prefix(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1741
def split_reference_container_prefix(line) prefix = String.new content = line.chomp while (split = split_blockquote_prefix(content)) prefix << split[0] content = split[1].chomp end [prefix, content] end
#split_table_row(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 991
def split_table_row(line) line.strip.sub(/\A\|/, '').sub(/\|\z/, '').split('|').map(&:strip) end
#store_placeholder(placeholders, html) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 832
def store_placeholder(placeholders, html) placeholders << html "\0#{placeholders.length - 1}\0" end
#strip_blockquote_marker(line) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2058
def strip_blockquote_marker(line) split = split_blockquote_prefix(line) split && split[1] end
#strip_fenced_indent(line, indent) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1079
def strip_fenced_indent(line, indent) return line.sub(/^\t/, '') if line.start_with?("\t") line.sub(/\A {0,#{indent}}/, '') end
#strip_list_item_indent(line, content_indent) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1637
def strip_list_item_indent(line, content_indent) consume_columns(line, content_indent, 0, true) end
#strip_trailing_punctuation(url) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1029
def strip_trailing_punctuation(url) trailer = '' while url =~ /[),.;:!?]\z/ trailer = url[-1, 1] + trailer url = url[0...-1] end [url, trailer] end
#table_alignment(cell) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 995
def table_alignment(cell) stripped = cell.strip return 'center' if stripped.start_with?(':') && stripped.end_with?(':') return 'left' if stripped.start_with?(':') return 'right' if stripped.end_with?(':') nil end
#table_row?(line) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 986
def table_row?(line) stripped = line.strip stripped.include?('|') && stripped !~ /\A[|:\-\s]+\z/ end
#table_start?(lines, index) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 981
def table_start?(lines, index) return false if index + 1 >= lines.length table_row?(lines[index]) && lines[index + 1] =~ TABLE_SEPARATOR_RE end
#thematic_break?(line) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 912
def thematic_break?(line) line =~ THEMATIC_BREAK_RE end
#to_html ⇒ String
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 96
def to_html parse_blocks(split_lines(@text), 0).join("\n") end
#unclosed_reference_title?(text) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1806
def unclosed_reference_title?(text) stripped = text.to_s.rstrip return false if stripped.empty? single_quotes = stripped.count("'") double_quotes = stripped.count('"') open_parens = stripped.count('(') close_parens = stripped.count(')') single_quotes.odd? || double_quotes.odd? || open_parens > close_parens end
#unescape_markdown_punctuation(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1893
def unescape_markdown_punctuation(text) text.to_s.gsub(ESCAPABLE_CHARS_RE, '\1') end
#unicode_casefold_compat(text) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2112
def unicode_casefold_compat(text) codepoints = text.to_s.unpack('U*') folded = String.new codepoints.each do |codepoint| append_folded_codepoint(folded, codepoint) end folded end
#unicode_symbol_char?(char) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1603
def unicode_symbol_char?(char) codepoint = char.to_s.unpack('U*').first return false unless codepoint (0x00A2..0x00A9).include?(codepoint) || (0x00AC..0x00AE).include?(codepoint) || (0x00B0..0x00B4).include?(codepoint) || codepoint == 0x00B6 || codepoint == 0x00B7 || codepoint == 0x00D7 || codepoint == 0x00F7 || (0x20A0..0x20CF).include?(codepoint) end
#unindent(lines) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1004
def unindent(lines) indent = lines.reject { |line| blank_line?(line) }.map do |line| leading_columns(line) end.min || 4 lines.map { |line| consume_columns(line, indent) }.join end
#unindent_indented_code(lines) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1012
def unindent_indented_code(lines) lines.map { |line| consume_columns(line, 4) }.join end
#utf8_bytes(char) (private)
[ GitHub ]# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 2104
def utf8_bytes(char) if defined?(Encoding) char.encode(Encoding::UTF_8).unpack('C*') else [char[0]].pack('U').unpack('C*') end end
#whitespace_char?(char) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 1593
def whitespace_char?(char) char.nil? || char =~ /\s/ || char == NAMED_ENTITIES['nbsp'] end
#yard_indented_code_start?(lines, index) ⇒ Boolean (private)
# File 'lib/yard/templates/helpers/markup/hybrid_markdown.rb', line 950
def yard_indented_code_start?(lines, index) return false unless leading_columns(lines[index]) >= 2 return false unless consume_columns(lines[index], 2) =~ /^!!!([\w.+-]+)[ \t]*$/ return false if index + 1 >= lines.length indented_code_block_start?(lines, index) && indented_code_start?(lines[index + 1]) end