Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/markdown_it/rules_block/blockquote.py: 99%

149 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:15 +0000

1# Block quotes 

2from __future__ import annotations 

3 

4import logging 

5 

6from ..common.utils import isStrSpace 

7from .state_block import StateBlock 

8 

9LOGGER = logging.getLogger(__name__) 

10 

11 

12def blockquote(state: StateBlock, startLine: int, endLine: int, silent: bool) -> bool: 

13 LOGGER.debug( 

14 "entering blockquote: %s, %s, %s, %s", state, startLine, endLine, silent 

15 ) 

16 

17 oldLineMax = state.lineMax 

18 pos = state.bMarks[startLine] + state.tShift[startLine] 

19 max = state.eMarks[startLine] 

20 

21 if state.is_code_block(startLine): 

22 return False 

23 

24 # check the block quote marker 

25 try: 

26 if state.src[pos] != ">": 

27 return False 

28 except IndexError: 

29 return False 

30 pos += 1 

31 

32 # we know that it's going to be a valid blockquote, 

33 # so no point trying to find the end of it in silent mode 

34 if silent: 

35 return True 

36 

37 # set offset past spaces and ">" 

38 initial = offset = state.sCount[startLine] + 1 

39 

40 try: 

41 second_char: str | None = state.src[pos] 

42 except IndexError: 

43 second_char = None 

44 

45 # skip one optional space after '>' 

46 if second_char == " ": 

47 # ' > test ' 

48 # ^ -- position start of line here: 

49 pos += 1 

50 initial += 1 

51 offset += 1 

52 adjustTab = False 

53 spaceAfterMarker = True 

54 elif second_char == "\t": 

55 spaceAfterMarker = True 

56 

57 if (state.bsCount[startLine] + offset) % 4 == 3: 

58 # ' >\t test ' 

59 # ^ -- position start of line here (tab has width==1) 

60 pos += 1 

61 initial += 1 

62 offset += 1 

63 adjustTab = False 

64 else: 

65 # ' >\t test ' 

66 # ^ -- position start of line here + shift bsCount slightly 

67 # to make extra space appear 

68 adjustTab = True 

69 

70 else: 

71 spaceAfterMarker = False 

72 

73 oldBMarks = [state.bMarks[startLine]] 

74 state.bMarks[startLine] = pos 

75 

76 while pos < max: 

77 ch = state.src[pos] 

78 

79 if isStrSpace(ch): 

80 if ch == "\t": 

81 offset += ( 

82 4 

83 - (offset + state.bsCount[startLine] + (1 if adjustTab else 0)) % 4 

84 ) 

85 else: 

86 offset += 1 

87 

88 else: 

89 break 

90 

91 pos += 1 

92 

93 oldBSCount = [state.bsCount[startLine]] 

94 state.bsCount[startLine] = ( 

95 state.sCount[startLine] + 1 + (1 if spaceAfterMarker else 0) 

96 ) 

97 

98 lastLineEmpty = pos >= max 

99 

100 oldSCount = [state.sCount[startLine]] 

101 state.sCount[startLine] = offset - initial 

102 

103 oldTShift = [state.tShift[startLine]] 

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

105 

106 terminatorRules = state.md.block.ruler.getRules("blockquote") 

107 

108 oldParentType = state.parentType 

109 state.parentType = "blockquote" 

110 

111 # Search the end of the block 

112 # 

113 # Block ends with either: 

114 # 1. an empty line outside: 

115 # ``` 

116 # > test 

117 # 

118 # ``` 

119 # 2. an empty line inside: 

120 # ``` 

121 # > 

122 # test 

123 # ``` 

124 # 3. another tag: 

125 # ``` 

126 # > test 

127 # - - - 

128 # ``` 

129 

130 # for (nextLine = startLine + 1; nextLine < endLine; nextLine++) { 

131 nextLine = startLine + 1 

132 while nextLine < endLine: 

133 # check if it's outdented, i.e. it's inside list item and indented 

134 # less than said list item: 

135 # 

136 # ``` 

137 # 1. anything 

138 # > current blockquote 

139 # 2. checking this line 

140 # ``` 

141 isOutdented = state.sCount[nextLine] < state.blkIndent 

142 

143 pos = state.bMarks[nextLine] + state.tShift[nextLine] 

144 max = state.eMarks[nextLine] 

145 

146 if pos >= max: 

147 # Case 1: line is not inside the blockquote, and this line is empty. 

148 break 

149 

150 evaluatesTrue = state.src[pos] == ">" and not isOutdented 

151 pos += 1 

152 if evaluatesTrue: 

153 # This line is inside the blockquote. 

154 

155 # set offset past spaces and ">" 

156 initial = offset = state.sCount[nextLine] + 1 

157 

158 try: 

159 next_char: str | None = state.src[pos] 

160 except IndexError: 

161 next_char = None 

162 

163 # skip one optional space after '>' 

164 if next_char == " ": 

165 # ' > test ' 

166 # ^ -- position start of line here: 

167 pos += 1 

168 initial += 1 

169 offset += 1 

170 adjustTab = False 

171 spaceAfterMarker = True 

172 elif next_char == "\t": 

173 spaceAfterMarker = True 

174 

175 if (state.bsCount[nextLine] + offset) % 4 == 3: 

176 # ' >\t test ' 

177 # ^ -- position start of line here (tab has width==1) 

178 pos += 1 

179 initial += 1 

180 offset += 1 

181 adjustTab = False 

182 else: 

183 # ' >\t test ' 

184 # ^ -- position start of line here + shift bsCount slightly 

185 # to make extra space appear 

186 adjustTab = True 

187 

188 else: 

189 spaceAfterMarker = False 

190 

191 oldBMarks.append(state.bMarks[nextLine]) 

192 state.bMarks[nextLine] = pos 

193 

194 while pos < max: 

195 ch = state.src[pos] 

196 

197 if isStrSpace(ch): 

198 if ch == "\t": 

199 offset += ( 

200 4 

201 - ( 

202 offset 

203 + state.bsCount[nextLine] 

204 + (1 if adjustTab else 0) 

205 ) 

206 % 4 

207 ) 

208 else: 

209 offset += 1 

210 else: 

211 break 

212 

213 pos += 1 

214 

215 lastLineEmpty = pos >= max 

216 

217 oldBSCount.append(state.bsCount[nextLine]) 

218 state.bsCount[nextLine] = ( 

219 state.sCount[nextLine] + 1 + (1 if spaceAfterMarker else 0) 

220 ) 

221 

222 oldSCount.append(state.sCount[nextLine]) 

223 state.sCount[nextLine] = offset - initial 

224 

225 oldTShift.append(state.tShift[nextLine]) 

226 state.tShift[nextLine] = pos - state.bMarks[nextLine] 

227 

228 nextLine += 1 

229 continue 

230 

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

232 if lastLineEmpty: 

233 break 

234 

235 # Case 3: another tag found. 

236 terminate = False 

237 

238 for terminatorRule in terminatorRules: 

239 if terminatorRule(state, nextLine, endLine, True): 

240 terminate = True 

241 break 

242 

243 if terminate: 

244 # Quirk to enforce "hard termination mode" for paragraphs; 

245 # normally if you call `tokenize(state, startLine, nextLine)`, 

246 # paragraphs will look below nextLine for paragraph continuation, 

247 # but if blockquote is terminated by another tag, they shouldn't 

248 state.lineMax = nextLine 

249 

250 if state.blkIndent != 0: 

251 # state.blkIndent was non-zero, we now set it to zero, 

252 # so we need to re-calculate all offsets to appear as 

253 # if indent wasn't changed 

254 oldBMarks.append(state.bMarks[nextLine]) 

255 oldBSCount.append(state.bsCount[nextLine]) 

256 oldTShift.append(state.tShift[nextLine]) 

257 oldSCount.append(state.sCount[nextLine]) 

258 state.sCount[nextLine] -= state.blkIndent 

259 

260 break 

261 

262 oldBMarks.append(state.bMarks[nextLine]) 

263 oldBSCount.append(state.bsCount[nextLine]) 

264 oldTShift.append(state.tShift[nextLine]) 

265 oldSCount.append(state.sCount[nextLine]) 

266 

267 # A negative indentation means that this is a paragraph continuation 

268 # 

269 state.sCount[nextLine] = -1 

270 

271 nextLine += 1 

272 

273 oldIndent = state.blkIndent 

274 state.blkIndent = 0 

275 

276 token = state.push("blockquote_open", "blockquote", 1) 

277 token.markup = ">" 

278 token.map = lines = [startLine, 0] 

279 

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

281 

282 token = state.push("blockquote_close", "blockquote", -1) 

283 token.markup = ">" 

284 

285 state.lineMax = oldLineMax 

286 state.parentType = oldParentType 

287 lines[1] = state.line 

288 

289 # Restore original tShift; this might not be necessary since the parser 

290 # has already been here, but just to make sure we can do that. 

291 for i, item in enumerate(oldTShift): 

292 state.bMarks[i + startLine] = oldBMarks[i] 

293 state.tShift[i + startLine] = item 

294 state.sCount[i + startLine] = oldSCount[i] 

295 state.bsCount[i + startLine] = oldBSCount[i] 

296 

297 state.blkIndent = oldIndent 

298 

299 return True