Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/markdown_it/rules_inline/strikethrough.py: 5%

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

97 statements  

1# ~~strike through~~ (and optionally ~single tilde~) 

2from __future__ import annotations 

3 

4from .state_inline import Delimiter, StateInline 

5 

6 

7def tokenize(state: StateInline, silent: bool) -> bool: 

8 """Insert each marker as a separate text token, and add it to delimiter list. 

9 

10 When the ``strikethrough_single_tilde`` option is enabled on the 

11 ``MarkdownIt`` instance, single ``~`` delimiters are also accepted and 

12 runs of three or more tildes are rejected (matching GitHub's rendering behaviour). 

13 """ 

14 start = state.pos 

15 ch = state.src[start] 

16 

17 if silent: 

18 return False 

19 

20 if ch != "~": 

21 return False 

22 

23 scanned = state.scanDelims(state.pos, True) 

24 length = scanned.length 

25 

26 single_tilde = state.md.options.get("strikethrough_single_tilde", False) 

27 

28 if single_tilde: 

29 # GitHub mode: only accept exactly 1 or 2 tildes. 

30 if length < 1: 

31 return False 

32 if length > 2: 

33 # Consume 3+ tildes as plain text so the parser doesn't 

34 # re-enter and match a subset of them. This intentionally 

35 # matches GitHub's rendering, where ≥3 tildes are literal text. 

36 token = state.push("text", "", 0) 

37 token.content = ch * length 

38 state.pos += scanned.length 

39 return True 

40 

41 token = state.push("text", "", 0) 

42 token.content = ch * length 

43 state.delimiters.append( 

44 Delimiter( 

45 marker=ord(ch), 

46 length=0, # disable "rule of 3" length checks 

47 token=len(state.tokens) - 1, 

48 end=-1, 

49 open=scanned.can_open, 

50 close=scanned.can_close, 

51 ) 

52 ) 

53 else: 

54 # Original markdown-it behaviour: minimum 2, split odd runs. 

55 if length < 2: 

56 return False 

57 

58 if length % 2: 

59 token = state.push("text", "", 0) 

60 token.content = ch 

61 length -= 1 

62 

63 i = 0 

64 while i < length: 

65 token = state.push("text", "", 0) 

66 token.content = ch + ch 

67 state.delimiters.append( 

68 Delimiter( 

69 marker=ord(ch), 

70 length=0, # disable "rule of 3" length checks 

71 token=len(state.tokens) - 1, 

72 end=-1, 

73 open=scanned.can_open, 

74 close=scanned.can_close, 

75 ) 

76 ) 

77 

78 i += 2 

79 

80 state.pos += scanned.length 

81 

82 return True 

83 

84 

85def _postProcess(state: StateInline, delimiters: list[Delimiter]) -> None: 

86 loneMarkers = [] 

87 maximum = len(delimiters) 

88 single_tilde = state.md.options.get("strikethrough_single_tilde", False) 

89 

90 i = 0 

91 while i < maximum: 

92 startDelim = delimiters[i] 

93 

94 if startDelim.marker != 0x7E: # /* ~ */ 

95 i += 1 

96 continue 

97 

98 if startDelim.end == -1: 

99 i += 1 

100 continue 

101 

102 endDelim = delimiters[startDelim.end] 

103 

104 # In single-tilde mode, opener and closer must have the same width 

105 # (both `~` or both `~~`). The width is stored in the text token. 

106 if single_tilde: 

107 opener_content = state.tokens[startDelim.token].content 

108 closer_content = state.tokens[endDelim.token].content 

109 if opener_content != closer_content: 

110 i += 1 

111 continue 

112 

113 markup = state.tokens[startDelim.token].content 

114 

115 token = state.tokens[startDelim.token] 

116 token.type = "s_open" 

117 token.tag = "s" 

118 token.nesting = 1 

119 token.markup = markup 

120 token.content = "" 

121 

122 token = state.tokens[endDelim.token] 

123 token.type = "s_close" 

124 token.tag = "s" 

125 token.nesting = -1 

126 token.markup = markup 

127 token.content = "" 

128 

129 if ( 

130 state.tokens[endDelim.token - 1].type == "text" 

131 and state.tokens[endDelim.token - 1].content == "~" 

132 ): 

133 loneMarkers.append(endDelim.token - 1) 

134 

135 i += 1 

136 

137 # If a marker sequence has an odd number of characters, it's split 

138 # like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the 

139 # start of the sequence. 

140 # 

141 # So, we have to move all those markers after subsequent s_close tags. 

142 # 

143 while loneMarkers: 

144 i = loneMarkers.pop() 

145 j = i + 1 

146 

147 while (j < len(state.tokens)) and (state.tokens[j].type == "s_close"): 

148 j += 1 

149 

150 j -= 1 

151 

152 if i != j: 

153 token = state.tokens[j] 

154 state.tokens[j] = state.tokens[i] 

155 state.tokens[i] = token 

156 

157 

158def postProcess(state: StateInline) -> None: 

159 """Walk through delimiter list and replace text tokens with tags.""" 

160 tokens_meta = state.tokens_meta 

161 maximum = len(state.tokens_meta) 

162 _postProcess(state, state.delimiters) 

163 

164 curr = 0 

165 while curr < maximum: 

166 try: 

167 curr_meta = tokens_meta[curr] 

168 except IndexError: 

169 pass 

170 else: 

171 if curr_meta and "delimiters" in curr_meta: 

172 _postProcess(state, curr_meta["delimiters"]) 

173 curr += 1