Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/markdown_it/parser_inline.py: 98%

61 statements  

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

1"""Tokenizes paragraph content. 

2""" 

3from __future__ import annotations 

4 

5from . import rules_inline 

6from .ruler import RuleFunc, Ruler 

7from .rules_inline.state_inline import StateInline 

8from .token import Token 

9 

10# Parser rules 

11_rules: list[tuple[str, RuleFunc]] = [ 

12 ("text", rules_inline.text), 

13 ("newline", rules_inline.newline), 

14 ("escape", rules_inline.escape), 

15 ("backticks", rules_inline.backtick), 

16 ("strikethrough", rules_inline.strikethrough.tokenize), 

17 ("emphasis", rules_inline.emphasis.tokenize), 

18 ("link", rules_inline.link), 

19 ("image", rules_inline.image), 

20 ("autolink", rules_inline.autolink), 

21 ("html_inline", rules_inline.html_inline), 

22 ("entity", rules_inline.entity), 

23] 

24 

25_rules2: list[tuple[str, RuleFunc]] = [ 

26 ("balance_pairs", rules_inline.link_pairs), 

27 ("strikethrough", rules_inline.strikethrough.postProcess), 

28 ("emphasis", rules_inline.emphasis.postProcess), 

29 ("text_collapse", rules_inline.text_collapse), 

30] 

31 

32 

33class ParserInline: 

34 def __init__(self): 

35 self.ruler = Ruler() 

36 for name, rule in _rules: 

37 self.ruler.push(name, rule) 

38 # Second ruler used for post-processing (e.g. in emphasis-like rules) 

39 self.ruler2 = Ruler() 

40 for name, rule2 in _rules2: 

41 self.ruler2.push(name, rule2) 

42 

43 def skipToken(self, state: StateInline) -> None: 

44 """Skip single token by running all rules in validation mode; 

45 returns `True` if any rule reported success 

46 """ 

47 ok = False 

48 pos = state.pos 

49 rules = self.ruler.getRules("") 

50 maxNesting = state.md.options["maxNesting"] 

51 cache = state.cache 

52 

53 if pos in cache: 

54 state.pos = cache[pos] 

55 return 

56 

57 if state.level < maxNesting: 

58 for rule in rules: 

59 # Increment state.level and decrement it later to limit recursion. 

60 # It's harmless to do here, because no tokens are created. 

61 # But ideally, we'd need a separate private state variable for this purpose. 

62 state.level += 1 

63 ok = rule(state, True) 

64 state.level -= 1 

65 if ok: 

66 break 

67 else: 

68 # Too much nesting, just skip until the end of the paragraph. 

69 # 

70 # NOTE: this will cause links to behave incorrectly in the following case, 

71 # when an amount of `[` is exactly equal to `maxNesting + 1`: 

72 # 

73 # [[[[[[[[[[[[[[[[[[[[[foo]() 

74 # 

75 # TODO: remove this workaround when CM standard will allow nested links 

76 # (we can replace it by preventing links from being parsed in 

77 # validation mode) 

78 # 

79 state.pos = state.posMax 

80 

81 if not ok: 

82 state.pos += 1 

83 cache[pos] = state.pos 

84 

85 def tokenize(self, state: StateInline) -> None: 

86 """Generate tokens for input range.""" 

87 ok = False 

88 rules = self.ruler.getRules("") 

89 end = state.posMax 

90 maxNesting = state.md.options["maxNesting"] 

91 

92 while state.pos < end: 

93 # Try all possible rules. 

94 # On success, rule should: 

95 # 

96 # - update `state.pos` 

97 # - update `state.tokens` 

98 # - return true 

99 

100 if state.level < maxNesting: 

101 for rule in rules: 

102 ok = rule(state, False) 

103 if ok: 

104 break 

105 

106 if ok: 

107 if state.pos >= end: 

108 break 

109 continue 

110 

111 state.pending += state.src[state.pos] 

112 state.pos += 1 

113 

114 if state.pending: 

115 state.pushPending() 

116 

117 def parse(self, src: str, md, env, tokens: list[Token]) -> list[Token]: 

118 """Process input string and push inline tokens into `tokens`""" 

119 state = StateInline(src, md, env, tokens) 

120 self.tokenize(state) 

121 rules2 = self.ruler2.getRules("") 

122 for rule in rules2: 

123 rule(state) 

124 return state.tokens