Class: MarkdownIt::RulesBlock::Blockquote

Inherits:
Object
  • Object
show all
Defined in:
lib/motion-markdown-it/rules_block/blockquote.rb

Class Method Summary collapse

Class Method Details

.blockquote(state, startLine, endLine, silent) ⇒ Object




8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/motion-markdown-it/rules_block/blockquote.rb', line 8

def self.blockquote(state, startLine, endLine, silent)
  pos = state.bMarks[startLine] + state.tShift[startLine]
  max = state.eMarks[startLine]

  # check the block quote marker
  return false if state.src.charCodeAt(pos) != 0x3E # >
  pos += 1
  
  # we know that it's going to be a valid blockquote,
  # so no point trying to find the end of it in silent mode
  return true if silent

  # skip one optional space after '>'
  pos += 1 if state.src.charCodeAt(pos) == 0x20

  oldIndent               = state.blkIndent
  state.blkIndent         = 0

  oldBMarks               = [ state.bMarks[startLine] ]
  state.bMarks[startLine] = pos

  # check if we have an empty blockquote
  pos                     = pos < max ? state.skipSpaces(pos) : pos
  lastLineEmpty           = pos >= max

  oldTShift               = [ state.tShift[startLine] ]
  state.tShift[startLine] = pos - state.bMarks[startLine]

  terminatorRules         = state.md.block.ruler.getRules('blockquote')

  # Search the end of the block
  #
  # Block ends with either:
  #  1. an empty line outside:
  #     ```
  #     > test
  #
  #     ```
  #  2. an empty line inside:
  #     ```
  #     >
  #     test
  #     ```
  #  3. another tag
  #     ```
  #     > test
  #      - - -
  #     ```
  nextLine = startLine + 1
  while nextLine < endLine
    pos = state.bMarks[nextLine] + state.tShift[nextLine]
    max = state.eMarks[nextLine]

    if pos >= max
      # Case 1: line is not inside the blockquote, and this line is empty.
      break
    end

    if state.src.charCodeAt(pos) == 0x3E   # >
      pos += 1
      # This line is inside the blockquote.

      # skip one optional space after '>'
      pos += 1 if state.src.charCodeAt(pos) == 0x20

      oldBMarks.push(state.bMarks[nextLine])
      state.bMarks[nextLine] = pos

      pos = pos < max ? state.skipSpaces(pos) : pos
      lastLineEmpty = pos >= max

      oldTShift.push(state.tShift[nextLine])
      state.tShift[nextLine] = pos - state.bMarks[nextLine]
      nextLine += 1
      next
    else
      pos += 1
    end

    # Case 2: line is not inside the blockquote, and the last line was empty.
    break if lastLineEmpty

    # Case 3: another tag found.
    terminate = false
    (0...terminatorRules.length).each do |i|
      if terminatorRules[i].call(state, nextLine, endLine, true)
        terminate = true
        break
      end
    end
    break if terminate

    oldBMarks.push(state.bMarks[nextLine])
    oldTShift.push(state.tShift[nextLine])

    # A negative number means that this is a paragraph continuation
    #
    # Any negative number will do the job here, but it's better for it
    # to be large enough to make any bugs obvious.
    state.tShift[nextLine] = -1337
    nextLine += 1
  end

  oldParentType    = state.parentType
  state.parentType = 'blockquote'

  token            = state.push('blockquote_open', 'blockquote', 1)
  token.markup     = '>'
  token.map        = lines = [ startLine, 0 ]

  state.md.block.tokenize(state, startLine, nextLine)

  token            = state.push('blockquote_close', 'blockquote', -1)
  token.markup     = '>'

  state.parentType = oldParentType
  lines[1]         = state.line

  # Restore original tShift; this might not be necessary since the parser
  # has already been here, but just to make sure we can do that.
  (0...oldTShift.length).each do |i|
    state.bMarks[i + startLine] = oldBMarks[i]
    state.tShift[i + startLine] = oldTShift[i]
  end
  state.blkIndent = oldIndent
  return true
end