1717
1818def longest_consecutive_sequence (seq : str , char : str ) -> int :
1919 """Return length of the longest consecutive sequence of `char` characters
20- in string `seq`."""
20+ in string `seq`.
21+
22+ This measured faster than the more "Pythonic"
23+
24+ ```
25+ max((len(list(g)) for k, g in groupby(s) if k == char), default=0)
26+ ```
27+ """
2128 assert len (char ) == 1
2229 longest = 0
2330 current_streak = 0
@@ -34,15 +41,16 @@ def longest_consecutive_sequence(seq: str, char: str) -> int:
3441def fence (node : "RenderTreeNode" , context : "RenderContext" ) -> str :
3542 """Render fences (and directives).
3643
37- Copied from upstream `mdformat` core and should be kept up-to-date
38- if upstream introduces changes. Note that only two lines are added
39- to the upstream implementation, i.e. the condition that calls
40- `format_directive_content` function.
44+ Originally copied from upstream `mdformat` core. Key changes so far:
45+ - call our `format_directive_content` function when a directive is detected (instead
46+ of treating the contents as code in that case).
47+ - allow colon fences (and use a heuristic to ensure good spacing when recombining
48+ those).
4149 """
4250 info_str = node .info .strip ()
4351 lang = info_str .split (maxsplit = 1 )[0 ] if info_str else ""
4452 is_directive = lang .startswith ("{" ) and lang .endswith ("}" )
45- code_block = node .content
53+ unformatted_body = node .content
4654
4755 # Info strings of backtick code fences can not contain backticks or tildes.
4856 # If that is the case, we make a tilde code fence instead.
@@ -53,11 +61,12 @@ def fence(node: "RenderTreeNode", context: "RenderContext") -> str:
5361 else :
5462 fence_char = "`"
5563
56- # Format the code block using enabled codeformatter funcs
57- if lang in context .options .get ("codeformatters" , {}):
64+ if is_directive :
65+ body = format_directive_content (unformatted_body , context = context )
66+ elif lang in context .options .get ("codeformatters" , {}):
5867 fmt_func = context .options ["codeformatters" ][lang ]
5968 try :
60- code_block = fmt_func (code_block , info_str )
69+ body = fmt_func (unformatted_body , info_str )
6170 except Exception :
6271 # Swallow exceptions so that formatter errors (e.g. due to
6372 # invalid code) do not crash mdformat.
@@ -66,18 +75,20 @@ def fence(node: "RenderTreeNode", context: "RenderContext") -> str:
6675 f"Failed formatting content of a { lang } code block "
6776 f"(line { node .map [0 ] + 1 } before formatting)"
6877 )
69- # This "elif" is the *only* thing added to the upstream `fence` implementation!
70- elif is_directive :
71- code_block = format_directive_content ( code_block , context = context )
78+ body = unformatted_body
79+ else :
80+ body = unformatted_body
7281
73- # The code block must not include as long or longer sequence of `fence_char`s
74- # as the fence string itself
75- fence_len = max (3 , longest_consecutive_sequence (code_block , fence_char ) + 1 )
82+ # The fenced contents must not include as long or longer sequence of `fence_char`s
83+ # as the fence string itself.
84+ fence_len = max (3 , longest_consecutive_sequence (body , fence_char ) + 1 )
7685 fence_str = fence_char * fence_len
7786 formatted_fence = f"{ fence_str } { info_str } \n "
78- if code_block .startswith (":::" ):
87+ # Heuristic to ensure child colon fences recombine with a leading blank line for
88+ # consistency.
89+ if body .startswith (":::" ):
7990 formatted_fence += "\n "
80- formatted_fence += f"{ code_block } { fence_str } "
91+ formatted_fence += f"{ body } { fence_str } "
8192 return formatted_fence
8293
8394
0 commit comments