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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

130 statements  

1import logging 

2 

3from ..common.utils import charCodeAt, isSpace, normalizeReference 

4from .state_block import StateBlock 

5 

6LOGGER = logging.getLogger(__name__) 

7 

8 

9def reference(state: StateBlock, startLine: int, _endLine: int, silent: bool) -> bool: 

10 LOGGER.debug( 

11 "entering reference: %s, %s, %s, %s", state, startLine, _endLine, silent 

12 ) 

13 

14 lines = 0 

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

16 maximum = state.eMarks[startLine] 

17 nextLine = startLine + 1 

18 

19 if state.is_code_block(startLine): 

20 return False 

21 

22 if state.src[pos] != "[": 

23 return False 

24 

25 # Simple check to quickly interrupt scan on [link](url) at the start of line. 

26 # Can be useful on practice: https:#github.com/markdown-it/markdown-it/issues/54 

27 while pos < maximum: 

28 # /* ] */ /* \ */ /* : */ 

29 if state.src[pos] == "]" and state.src[pos - 1] != "\\": 

30 if pos + 1 == maximum: 

31 return False 

32 if state.src[pos + 1] != ":": 

33 return False 

34 break 

35 pos += 1 

36 

37 endLine = state.lineMax 

38 

39 # jump line-by-line until empty one or EOF 

40 terminatorRules = state.md.block.ruler.getRules("reference") 

41 

42 oldParentType = state.parentType 

43 state.parentType = "reference" 

44 

45 while nextLine < endLine and not state.isEmpty(nextLine): 

46 # this would be a code block normally, but after paragraph 

47 # it's considered a lazy continuation regardless of what's there 

48 if state.sCount[nextLine] - state.blkIndent > 3: 

49 nextLine += 1 

50 continue 

51 

52 # quirk for blockquotes, this line should already be checked by that rule 

53 if state.sCount[nextLine] < 0: 

54 nextLine += 1 

55 continue 

56 

57 # Some tags can terminate paragraph without empty line. 

58 terminate = False 

59 for terminatorRule in terminatorRules: 

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

61 terminate = True 

62 break 

63 

64 if terminate: 

65 break 

66 

67 nextLine += 1 

68 

69 string = state.getLines(startLine, nextLine, state.blkIndent, False).strip() 

70 maximum = len(string) 

71 

72 labelEnd = None 

73 pos = 1 

74 while pos < maximum: 

75 ch = charCodeAt(string, pos) 

76 if ch == 0x5B: # /* [ */ 

77 return False 

78 elif ch == 0x5D: # /* ] */ 

79 labelEnd = pos 

80 break 

81 elif ch == 0x0A: # /* \n */ 

82 lines += 1 

83 elif ch == 0x5C: # /* \ */ 

84 pos += 1 

85 if pos < maximum and charCodeAt(string, pos) == 0x0A: 

86 lines += 1 

87 pos += 1 

88 

89 if ( 

90 labelEnd is None or labelEnd < 0 or charCodeAt(string, labelEnd + 1) != 0x3A 

91 ): # /* : */ 

92 return False 

93 

94 # [label]: destination 'title' 

95 # ^^^ skip optional whitespace here 

96 pos = labelEnd + 2 

97 while pos < maximum: 

98 ch = charCodeAt(string, pos) 

99 if ch == 0x0A: 

100 lines += 1 

101 elif isSpace(ch): 

102 pass 

103 else: 

104 break 

105 pos += 1 

106 

107 # [label]: destination 'title' 

108 # ^^^^^^^^^^^ parse this 

109 res = state.md.helpers.parseLinkDestination(string, pos, maximum) 

110 if not res.ok: 

111 return False 

112 

113 href = state.md.normalizeLink(res.str) 

114 if not state.md.validateLink(href): 

115 return False 

116 

117 pos = res.pos 

118 lines += res.lines 

119 

120 # save cursor state, we could require to rollback later 

121 destEndPos = pos 

122 destEndLineNo = lines 

123 

124 # [label]: destination 'title' 

125 # ^^^ skipping those spaces 

126 start = pos 

127 while pos < maximum: 

128 ch = charCodeAt(string, pos) 

129 if ch == 0x0A: 

130 lines += 1 

131 elif isSpace(ch): 

132 pass 

133 else: 

134 break 

135 pos += 1 

136 

137 # [label]: destination 'title' 

138 # ^^^^^^^ parse this 

139 res = state.md.helpers.parseLinkTitle(string, pos, maximum) 

140 if pos < maximum and start != pos and res.ok: 

141 title = res.str 

142 pos = res.pos 

143 lines += res.lines 

144 else: 

145 title = "" 

146 pos = destEndPos 

147 lines = destEndLineNo 

148 

149 # skip trailing spaces until the rest of the line 

150 while pos < maximum: 

151 ch = charCodeAt(string, pos) 

152 if not isSpace(ch): 

153 break 

154 pos += 1 

155 

156 if pos < maximum and charCodeAt(string, pos) != 0x0A and title: 

157 # garbage at the end of the line after title, 

158 # but it could still be a valid reference if we roll back 

159 title = "" 

160 pos = destEndPos 

161 lines = destEndLineNo 

162 while pos < maximum: 

163 ch = charCodeAt(string, pos) 

164 if not isSpace(ch): 

165 break 

166 pos += 1 

167 

168 if pos < maximum and charCodeAt(string, pos) != 0x0A: 

169 # garbage at the end of the line 

170 return False 

171 

172 label = normalizeReference(string[1:labelEnd]) 

173 if not label: 

174 # CommonMark 0.20 disallows empty labels 

175 return False 

176 

177 # Reference can not terminate anything. This check is for safety only. 

178 if silent: 

179 return True 

180 

181 if "references" not in state.env: 

182 state.env["references"] = {} 

183 

184 state.line = startLine + lines + 1 

185 

186 # note, this is not part of markdown-it JS, but is useful for renderers 

187 if state.md.options.get("inline_definitions", False): 

188 token = state.push("definition", "", 0) 

189 token.meta = { 

190 "id": label, 

191 "title": title, 

192 "url": href, 

193 "label": string[1:labelEnd], 

194 } 

195 token.map = [startLine, state.line] 

196 

197 if label not in state.env["references"]: 

198 state.env["references"][label] = { 

199 "title": title, 

200 "href": href, 

201 "map": [startLine, state.line], 

202 } 

203 else: 

204 state.env.setdefault("duplicate_refs", []).append( 

205 { 

206 "title": title, 

207 "href": href, 

208 "label": label, 

209 "map": [startLine, state.line], 

210 } 

211 ) 

212 

213 state.parentType = oldParentType 

214 

215 return True