class MotionMarkdownItPlugins::Deflist

Public Class Methods

deflist(state, startLine, endLine, silent) click to toggle source
# File lib/motion-markdown-it-plugins/deflist/deflist.rb, line 58
def self.deflist(state, startLine, endLine, silent)
  if silent
    # quirk: validation mode validates a dd block only, not a whole deflist
    return false if (state.ddIndent < 0)
    return skipMarker(state, startLine) >= 0
  end

  nextLine = startLine + 1
  return false if nextLine >= endLine

  if state.isEmpty(nextLine)
    nextLine += 1
    return false if nextLine >= endLine
  end

  return false if (state.sCount[nextLine] < state.blkIndent)
  contentStart = skipMarker(state, nextLine)
  return false if (contentStart < 0)

  # Start list
  listTokIdx = state.tokens.length
  tight      = true

  token      = state.push('dl_open', 'dl', 1)
  token.map  = listLines = [ startLine, 0 ]

  #
  # Iterate list items
  #

  dtLine = startLine
  ddLine = nextLine

  # One definition list can contain multiple DTs,
  # and one DT can be followed by multiple DDs.
  #
  # Thus, there is two loops here, and label is
  # needed to break out of the second one
  # OUTER:
  while true
    break_outer    = false
    prevEmptyEnd   = false

    token          = state.push('dt_open', 'dt', 1)
    token.map      = [ dtLine, dtLine ]

    token          = state.push('inline', '', 0)
    token.map      = [ dtLine, dtLine ]
    token.content  = state.getLines(dtLine, dtLine + 1, state.blkIndent, false).strip
    token.children = []

    token          = state.push('dt_close', 'dt', -1)

    while true
      token     = state.push('dd_open', 'dd', 1)
      token.map = itemLines = [ nextLine, 0 ]

      pos    = contentStart
      max    = state.eMarks[ddLine]
      offset = state.sCount[ddLine] + contentStart - (state.bMarks[ddLine] + state.tShift[ddLine])

      while pos < max
        ch = charCodeAt(state.src, pos)

        if isSpace(ch)
          if ch == 0x09
            offset += 4 - offset % 4
          else
            offset += 1
          end
        else
          break
        end

        pos += 1
      end

      contentStart = pos

      oldTight             = state.tight
      oldDDIndent          = state.ddIndent
      oldIndent            = state.blkIndent
      oldTShift            = state.tShift[ddLine]
      oldSCount            = state.sCount[ddLine]
      oldParentType        = state.parentType
      state.blkIndent      = state.ddIndent = state.sCount[ddLine] + 2
      state.tShift[ddLine] = contentStart - state.bMarks[ddLine]
      state.sCount[ddLine] = offset
      state.tight          = true
      state.parentType     = 'deflist'

      state.md.block.tokenize(state, ddLine, endLine, true)

      # If any of list item is tight, mark list as tight
      if (!state.tight || prevEmptyEnd)
        tight = false
      end
      # Item become loose if finish with empty line,
      # but we should filter last element, because it means list finish
      prevEmptyEnd = (state.line - ddLine) > 1 && state.isEmpty(state.line - 1)

      state.tShift[ddLine] = oldTShift
      state.sCount[ddLine] = oldSCount
      state.tight          = oldTight
      state.parentType     = oldParentType
      state.blkIndent      = oldIndent
      state.ddIndent       = oldDDIndent

      token = state.push('dd_close', 'dd', -1)

      itemLines[1] = nextLine = state.line

      break_outer = true and break if (nextLine >= endLine)
      break_outer = true and break if (state.sCount[nextLine] < state.blkIndent)
      contentStart = skipMarker(state, nextLine)
      break if (contentStart < 0)

      ddLine = nextLine

      # go to the next loop iteration:
      # insert DD tag and repeat checking
    end
    break if break_outer

    break if (nextLine >= endLine)
    dtLine = nextLine

    break if (state.isEmpty(dtLine))
    break if (state.sCount[dtLine] < state.blkIndent)

    ddLine = dtLine + 1
    break if (ddLine >= endLine)
    ddLine += 1 if (state.isEmpty(ddLine))
    break if (ddLine >= endLine)

    break if (state.sCount[ddLine] < state.blkIndent)
    contentStart = skipMarker(state, ddLine)
    break if (contentStart < 0)

    # go to the next loop iteration:
    # insert DT and DD tags and repeat checking
  end

  # Finalize list
  token        = state.push('dl_close', 'dl', -1)
  listLines[1] = nextLine
  state.line   = nextLine

  # mark paragraphs tight if needed
  if (tight)
    markTightParagraphs(state, listTokIdx)
  end

  return true
end
init_plugin(md) click to toggle source
# File lib/motion-markdown-it-plugins/deflist/deflist.rb, line 11
def self.init_plugin(md)
  md.block.ruler.before('paragraph', 'deflist',
      lambda { |state, startLine, endLine, silent| Deflist.deflist(state, startLine, endLine, silent) },
      {alt: ['', 'paragraph', 'reference']})
end
markTightParagraphs(state, idx) click to toggle source
# File lib/motion-markdown-it-plugins/deflist/deflist.rb, line 43
def self.markTightParagraphs(state, idx)
  level = state.level + 2
  i     = idx + 2
  l     = state.tokens.length - 2
  while i < l
    if (state.tokens[i].level == level && state.tokens[i].type == 'paragraph_open')
      state.tokens[i + 2].hidden = true
      state.tokens[i].hidden     = true
      i += 2
    end
    i += 1
  end
end
skipMarker(state, line) click to toggle source

Search `[:~][n ]`, returns next pos after marker on success or -1 on fail.

# File lib/motion-markdown-it-plugins/deflist/deflist.rb, line 20
def self.skipMarker(state, line)
  start = state.bMarks[line] + state.tShift[line]
  max   = state.eMarks[line]

  return -1 if (start >= max)

  # Check bullet
  marker = charCodeAt(state.src, start)
  start += 1
  return -1 if (marker != 0x7E && marker != 0x3A) #  '~'  ':'

  pos = state.skipSpaces(start)

  # require space after ":"
  return -1 if (start == pos)

  # no empty definitions, e.g. "  : "
  return -1 if (pos >= max)

  return start
end