class MarkdownIt::RulesBlock::Reference
Public Class Methods
reference(state, startLine, _endLine, silent)
click to toggle source
# File lib/motion-markdown-it/rules_block/reference.rb, line 7 def self.reference(state, startLine, _endLine, silent) lines = 0 pos = state.bMarks[startLine] + state.tShift[startLine] max = state.eMarks[startLine] nextLine = startLine + 1 # if it's indented more than 3 spaces, it should be a code block return false if state.sCount[startLine] - state.blkIndent >= 4 return false if charCodeAt(state.src, pos) != 0x5B # [ # Simple check to quickly interrupt scan on [link](url) at the start of line. # Can be useful on practice: https://github.com/markdown-it/markdown-it/issues/54 pos += 1 while (pos < max) if (charCodeAt(state.src, pos) == 0x5D && # ] charCodeAt(state.src, pos - 1) != 0x5C) # \ return false if (pos + 1 === max) return false if (charCodeAt(state.src, pos + 1) != 0x3A) # : break end pos += 1 end endLine = state.lineMax # jump line-by-line until empty one or EOF terminatorRules = state.md.block.ruler.getRules('reference') oldParentType = state.parentType state.parentType = 'reference' while nextLine < endLine && !state.isEmpty(nextLine) # this would be a code block normally, but after paragraph # it's considered a lazy continuation regardless of what's there (nextLine += 1) and next if (state.sCount[nextLine] - state.blkIndent > 3) # quirk for blockquotes, this line should already be checked by that rule (nextLine += 1) and next if state.sCount[nextLine] < 0 # Some tags can terminate paragraph without empty line. terminate = false (0...terminatorRules.length).each do |i| if (terminatorRules[i].call(state, nextLine, endLine, true)) terminate = true break end end break if (terminate) nextLine += 1 end str = state.getLines(startLine, nextLine, state.blkIndent, false).strip max = str.length labelEnd = -1 pos = 1 while pos < max ch = charCodeAt(str, pos) if (ch == 0x5B ) # [ return false elsif (ch == 0x5D) # ] labelEnd = pos break elsif (ch == 0x0A) # \n lines += 1 elsif (ch == 0x5C) # \ pos += 1 if (pos < max && charCodeAt(str, pos) == 0x0A) lines += 1 end end pos += 1 end return false if (labelEnd < 0 || charCodeAt(str, labelEnd + 1) != 0x3A) # : # [label]: destination 'title' # ^^^ skip optional whitespace here pos = labelEnd + 2 while pos < max ch = charCodeAt(str, pos) if (ch == 0x0A) lines += 1 elsif isSpace(ch) else break end pos += 1 end # [label]: destination 'title' # ^^^^^^^^^^^ parse this res = state.md.helpers.parseLinkDestination(str, pos, max) return false if (!res[:ok]) href = state.md.normalizeLink.call(res[:str]) return false if (!state.md.validateLink.call(href)) pos = res[:pos] lines += res[:lines] # save cursor state, we could require to rollback later destEndPos = pos destEndLineNo = lines # [label]: destination 'title' # ^^^ skipping those spaces start = pos while (pos < max) ch = charCodeAt(str, pos) if (ch == 0x0A) lines += 1 elsif isSpace(ch) else break end pos += 1 end # [label]: destination 'title' # ^^^^^^^ parse this res = state.md.helpers.parseLinkTitle(str, pos, max) if (pos < max && start != pos && res[:ok]) title = res[:str] pos = res[:pos] lines += res[:lines] else title = '' pos = destEndPos lines = destEndLineNo end # skip trailing spaces until the rest of the line while pos < max ch = charCodeAt(str, pos) break if !isSpace(ch) pos += 1 end if (pos < max && charCodeAt(str, pos) != 0x0A) if (title) # garbage at the end of the line after title, # but it could still be a valid reference if we roll back title = '' pos = destEndPos lines = destEndLineNo while pos < max ch = charCodeAt(str, pos) break if !isSpace(ch) pos += 1 end end end if (pos < max && charCodeAt(str, pos) != 0x0A) # garbage at the end of the line return false end label = normalizeReference(str.slice(1...labelEnd)) if label == '' # CommonMark 0.20 disallows empty labels return false end # Reference can not terminate anything. This check is for safety only. # istanbul ignore if return true if (silent) if (state.env[:references].nil?) state.env[:references] = {} end if state.env[:references][label].nil? state.env[:references][label] = { title: title, href: href } end state.parentType = oldParentType state.line = startLine + lines + 1 return true end