Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/mdit_py_plugins/myst_role/index.py: 83%

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

47 statements  

1from collections.abc import Sequence 

2import re 

3from typing import TYPE_CHECKING 

4 

5from markdown_it import MarkdownIt 

6from markdown_it.common.utils import escapeHtml 

7from markdown_it.rules_inline import StateInline 

8 

9if TYPE_CHECKING: 

10 from markdown_it.renderer import RendererProtocol 

11 from markdown_it.token import Token 

12 from markdown_it.utils import EnvType, OptionsDict 

13 

14VALID_NAME_PATTERN = re.compile(r"^\{([a-zA-Z0-9\_\-\+\:]+)\}") 

15 

16 

17def myst_role_plugin(md: MarkdownIt) -> None: 

18 """Parse ``{role-name}`content```""" 

19 md.inline.ruler.before("backticks", "myst_role", myst_role) 

20 md.add_render_rule("myst_role", render_myst_role) 

21 

22 

23def myst_role(state: StateInline, silent: bool) -> bool: 

24 # check name 

25 match = VALID_NAME_PATTERN.match(state.src[state.pos :]) 

26 if not match: 

27 return False 

28 name = match.group(1) 

29 

30 # check for starting backslash escape 

31 try: 

32 if state.src[state.pos - 1] == "\\": 

33 # escaped (this could be improved in the case of edge case '\\{') 

34 return False 

35 except IndexError: 

36 pass 

37 

38 # scan opening tick length 

39 start = pos = state.pos + match.end() 

40 try: 

41 while state.src[pos] == "`": 

42 pos += 1 

43 except IndexError: 

44 return False 

45 

46 tick_length = pos - start 

47 if not tick_length: 

48 return False 

49 

50 # search for closing ticks 

51 match = re.search("`" * tick_length, state.src[pos + 1 :]) 

52 if not match: 

53 return False 

54 content = state.src[pos : pos + match.start() + 1].replace("\n", " ") 

55 

56 if not silent: 

57 token = state.push("myst_role", "", 0) 

58 token.meta = {"name": name} 

59 token.content = content 

60 

61 state.pos = pos + match.end() + 1 

62 

63 return True 

64 

65 

66def render_myst_role( 

67 self: "RendererProtocol", 

68 tokens: Sequence["Token"], 

69 idx: int, 

70 options: "OptionsDict", 

71 env: "EnvType", 

72) -> str: 

73 token = tokens[idx] 

74 name = token.meta.get("name", "unknown") 

75 return f'<code class="myst role">{{{name}}}[{escapeHtml(token.content)}]</code>'