Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/mdit_py_plugins/front_matter/index.py: 98%

64 statements  

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

1"""Process front matter.""" 

2from markdown_it import MarkdownIt 

3from markdown_it.rules_block import StateBlock 

4 

5from mdit_py_plugins.utils import is_code_block 

6 

7 

8def front_matter_plugin(md: MarkdownIt) -> None: 

9 """Plugin ported from 

10 `markdown-it-front-matter <https://github.com/ParkSB/markdown-it-front-matter>`__. 

11 

12 It parses initial metadata, stored between opening/closing dashes: 

13 

14 .. code-block:: md 

15 

16 --- 

17 valid-front-matter: true 

18 --- 

19 

20 """ 

21 md.block.ruler.before( 

22 "table", 

23 "front_matter", 

24 _front_matter_rule, 

25 {"alt": ["paragraph", "reference", "blockquote", "list"]}, 

26 ) 

27 

28 

29def _front_matter_rule( 

30 state: StateBlock, startLine: int, endLine: int, silent: bool 

31) -> bool: 

32 marker_chr = "-" 

33 min_markers = 3 

34 

35 auto_closed = False 

36 start = state.bMarks[startLine] + state.tShift[startLine] 

37 maximum = state.eMarks[startLine] 

38 src_len = len(state.src) 

39 

40 # Check out the first character of the first line quickly, 

41 # this should filter out non-front matter 

42 if startLine != 0 or state.src[0] != marker_chr: 

43 return False 

44 

45 # Check out the rest of the marker string 

46 # while pos <= 3 

47 pos = start + 1 

48 while pos <= maximum and pos < src_len: 

49 if state.src[pos] != marker_chr: 

50 break 

51 pos += 1 

52 

53 marker_count = pos - start 

54 

55 if marker_count < min_markers: 

56 return False 

57 

58 # Since start is found, we can report success here in validation mode 

59 if silent: 

60 return True 

61 

62 # Search for the end of the block 

63 nextLine = startLine 

64 

65 while True: 

66 nextLine += 1 

67 if nextLine >= endLine: 

68 # unclosed block should be autoclosed by end of document. 

69 return False 

70 

71 if state.src[start:maximum] == "...": 

72 break 

73 

74 start = state.bMarks[nextLine] + state.tShift[nextLine] 

75 maximum = state.eMarks[nextLine] 

76 

77 if start < maximum and state.sCount[nextLine] < state.blkIndent: 

78 # non-empty line with negative indent should stop the list: 

79 # - ``` 

80 # test 

81 break 

82 

83 if state.src[start] != marker_chr: 

84 continue 

85 

86 if is_code_block(state, nextLine): 

87 continue 

88 

89 pos = start + 1 

90 while pos < maximum: 

91 if state.src[pos] != marker_chr: 

92 break 

93 pos += 1 

94 

95 # closing code fence must be at least as long as the opening one 

96 if (pos - start) < marker_count: 

97 continue 

98 

99 # make sure tail has spaces only 

100 pos = state.skipSpaces(pos) 

101 

102 if pos < maximum: 

103 continue 

104 

105 # found! 

106 auto_closed = True 

107 break 

108 

109 old_parent = state.parentType 

110 old_line_max = state.lineMax 

111 state.parentType = "container" 

112 

113 # this will prevent lazy continuations from ever going past our end marker 

114 state.lineMax = nextLine 

115 

116 token = state.push("front_matter", "", 0) 

117 token.hidden = True 

118 token.markup = marker_chr * min_markers 

119 token.content = state.src[state.bMarks[startLine + 1] : state.eMarks[nextLine - 1]] 

120 token.block = True 

121 

122 state.parentType = old_parent 

123 state.lineMax = old_line_max 

124 state.line = nextLine + (1 if auto_closed else 0) 

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

126 

127 return True