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

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

52 statements  

1"""Block-level tokenizer.""" 

2 

3from __future__ import annotations 

4 

5from collections.abc import Callable 

6import logging 

7from typing import TYPE_CHECKING 

8 

9from . import rules_block 

10from .ruler import Ruler 

11from .rules_block.state_block import StateBlock 

12from .token import Token 

13from .utils import EnvType 

14 

15if TYPE_CHECKING: 

16 from markdown_it import MarkdownIt 

17 

18LOGGER = logging.getLogger(__name__) 

19 

20 

21RuleFuncBlockType = Callable[[StateBlock, int, int, bool], bool] 

22"""(state: StateBlock, startLine: int, endLine: int, silent: bool) -> matched: bool) 

23 

24`silent` disables token generation, useful for lookahead. 

25""" 

26 

27_rules: list[tuple[str, RuleFuncBlockType, list[str]]] = [ 

28 # First 2 params - rule name & source. Secondary array - list of rules, 

29 # which can be terminated by this one. 

30 ("table", rules_block.table, ["paragraph", "reference"]), 

31 ("code", rules_block.code, []), 

32 ("fence", rules_block.fence, ["paragraph", "reference", "blockquote", "list"]), 

33 ( 

34 "blockquote", 

35 rules_block.blockquote, 

36 ["paragraph", "reference", "blockquote", "list"], 

37 ), 

38 ("hr", rules_block.hr, ["paragraph", "reference", "blockquote", "list"]), 

39 ("list", rules_block.list_block, ["paragraph", "reference", "blockquote"]), 

40 ("reference", rules_block.reference, []), 

41 ("html_block", rules_block.html_block, ["paragraph", "reference", "blockquote"]), 

42 ("heading", rules_block.heading, ["paragraph", "reference", "blockquote"]), 

43 ("lheading", rules_block.lheading, []), 

44 ("paragraph", rules_block.paragraph, []), 

45] 

46 

47 

48class ParserBlock: 

49 """ 

50 ParserBlock#ruler -> Ruler 

51 

52 [[Ruler]] instance. Keep configuration of block rules. 

53 """ 

54 

55 def __init__(self) -> None: 

56 self.ruler = Ruler[RuleFuncBlockType]() 

57 for name, rule, alt in _rules: 

58 self.ruler.push(name, rule, {"alt": alt}) 

59 

60 def tokenize(self, state: StateBlock, startLine: int, endLine: int) -> None: 

61 """Generate tokens for input range.""" 

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

63 line = startLine 

64 maxNesting = state.md.options.maxNesting 

65 hasEmptyLines = False 

66 

67 while line < endLine: 

68 state.line = line = state.skipEmptyLines(line) 

69 if line >= endLine: 

70 break 

71 if state.sCount[line] < state.blkIndent: 

72 # Termination condition for nested calls. 

73 # Nested calls currently used for blockquotes & lists 

74 break 

75 if state.level >= maxNesting: 

76 # If nesting level exceeded - skip tail to the end. 

77 # That's not ordinary situation and we should not care about content. 

78 state.line = endLine 

79 break 

80 

81 # Try all possible rules. 

82 # On success, rule should: 

83 # - update `state.line` 

84 # - update `state.tokens` 

85 # - return True 

86 for rule in rules: 

87 if rule(state, line, endLine, False): 

88 break 

89 

90 # set state.tight if we had an empty line before current tag 

91 # i.e. latest empty line should not count 

92 state.tight = not hasEmptyLines 

93 

94 line = state.line 

95 

96 # paragraph might "eat" one newline after it in nested lists 

97 if (line - 1) < endLine and state.isEmpty(line - 1): 

98 hasEmptyLines = True 

99 

100 if line < endLine and state.isEmpty(line): 

101 hasEmptyLines = True 

102 line += 1 

103 state.line = line 

104 

105 def parse( 

106 self, src: str, md: MarkdownIt, env: EnvType, outTokens: list[Token] 

107 ) -> list[Token] | None: 

108 """Process input string and push block tokens into `outTokens`.""" 

109 if not src: 

110 return None 

111 state = StateBlock(src, md, env, outTokens) 

112 self.tokenize(state, state.line, state.lineMax) 

113 return state.tokens