@@ -1879,8 +1879,6 @@ def _code_block_sub(self, match, is_fenced_code_block=False):
18791879 lexer_name = None
18801880 if is_fenced_code_block :
18811881 lexer_name = match .group (2 )
1882- if lexer_name :
1883- formatter_opts = self .extras ['fenced-code-blocks' ] or {}
18841882 codeblock = match .group (3 )
18851883 codeblock = codeblock [:- 1 ] # drop one trailing newline
18861884 else :
@@ -1895,43 +1893,62 @@ def _code_block_sub(self, match, is_fenced_code_block=False):
18951893 lexer_name , rest = codeblock .split ('\n ' , 1 )
18961894 lexer_name = lexer_name [3 :].strip ()
18971895 codeblock = rest .lstrip ("\n " ) # Remove lexer declaration line.
1898- formatter_opts = self .extras ['code-color' ] or {}
18991896
19001897 # Use pygments only if not using the highlightjs-lang extra
19011898 if lexer_name and "highlightjs-lang" not in self .extras :
1902- def unhash_code (codeblock ):
1903- for key , sanitized in list (self .html_spans .items ()):
1904- codeblock = codeblock .replace (key , sanitized )
1905- replacements = [
1906- ("&" , "&" ),
1907- ("<" , "<" ),
1908- (">" , ">" )
1909- ]
1910- for old , new in replacements :
1911- codeblock = codeblock .replace (old , new )
1912- return codeblock
19131899 lexer = self ._get_pygments_lexer (lexer_name )
19141900 if lexer :
1915- # remove leading indent from code block
1916- leading_indent , codeblock = self ._uniform_outdent (codeblock )
1901+ leading_indent = ' ' * ( len ( match . group ( 1 )) - len ( match . group ( 1 ). lstrip ()))
1902+ return self ._code_block_with_lexer_sub (codeblock , leading_indent , lexer , is_fenced_code_block )
19171903
1918- codeblock = unhash_code ( codeblock )
1919- colored = self ._color_with_pygments (codeblock , lexer ,
1920- ** formatter_opts )
1921-
1922- # add back the indent to all lines
1923- return "\n %s\n " % self ._uniform_indent (colored , leading_indent , True )
1924-
1925- codeblock = self ._encode_code (codeblock )
19261904 pre_class_str = self ._html_class_str_from_tag ("pre" )
19271905
19281906 if "highlightjs-lang" in self .extras and lexer_name :
19291907 code_class_str = ' class="%s language-%s"' % (lexer_name , lexer_name )
19301908 else :
19311909 code_class_str = self ._html_class_str_from_tag ("code" )
19321910
1933- return "\n <pre%s><code%s>%s\n </code></pre>\n " % (
1934- pre_class_str , code_class_str , codeblock )
1911+ if is_fenced_code_block :
1912+ # Fenced code blocks need to be outdented before encoding, and then reapplied
1913+ leading_indent = ' ' * (len (match .group (1 )) - len (match .group (1 ).lstrip ()))
1914+ leading_indent , codeblock = self ._uniform_outdent_limit (codeblock , leading_indent )
1915+
1916+ codeblock = self ._encode_code (codeblock )
1917+
1918+ return "\n %s<pre%s><code%s>%s\n </code></pre>\n " % (
1919+ leading_indent , pre_class_str , code_class_str , codeblock )
1920+ else :
1921+ codeblock = self ._encode_code (codeblock )
1922+
1923+ return "\n <pre%s><code%s>%s\n </code></pre>\n " % (
1924+ pre_class_str , code_class_str , codeblock )
1925+
1926+ def _code_block_with_lexer_sub (self , codeblock , leading_indent , lexer , is_fenced_code_block ):
1927+ if is_fenced_code_block :
1928+ formatter_opts = self .extras ['fenced-code-blocks' ] or {}
1929+ else :
1930+ formatter_opts = self .extras ['code-color' ] or {}
1931+
1932+ def unhash_code (codeblock ):
1933+ for key , sanitized in list (self .html_spans .items ()):
1934+ codeblock = codeblock .replace (key , sanitized )
1935+ replacements = [
1936+ ("&" , "&" ),
1937+ ("<" , "<" ),
1938+ (">" , ">" )
1939+ ]
1940+ for old , new in replacements :
1941+ codeblock = codeblock .replace (old , new )
1942+ return codeblock
1943+ # remove leading indent from code block
1944+ leading_indent , codeblock = self ._uniform_outdent (codeblock )
1945+
1946+ codeblock = unhash_code ( codeblock )
1947+ colored = self ._color_with_pygments (codeblock , lexer ,
1948+ ** formatter_opts )
1949+
1950+ # add back the indent to all lines
1951+ return "\n %s\n " % self ._uniform_indent (colored , leading_indent , True )
19351952
19361953 def _html_class_str_from_tag (self , tag ):
19371954 """Get the appropriate ' class="..."' string (note the leading
@@ -2444,6 +2461,8 @@ def _uniform_outdent(self, text):
24442461
24452462 # Find leading indentation of each line
24462463 ws = re .findall (r'(^[ \t]*)(?:[^ \t\n])' , text , re .MULTILINE )
2464+ if not ws :
2465+ return '' , text
24472466 # Get smallest common leading indent
24482467 ws = sorted (ws )[0 ]
24492468 # Dedent every line by smallest common indent
@@ -2452,6 +2471,26 @@ def _uniform_outdent(self, text):
24522471 for line in text .splitlines (True )
24532472 )
24542473
2474+ def _uniform_outdent_limit (self , text , outdent ):
2475+ # Outdents up to `outdent`. Similar to `_uniform_outdent`, but
2476+ # will leave some indentation on the line with the smallest common
2477+ # leading indentation depending on the amount specified.
2478+ # If the smallest leading indentation is less than `outdent`, it will
2479+ # perform identical to `_uniform_outdent`
2480+
2481+ # Find leading indentation of each line
2482+ ws = re .findall (r'(^[ \t]*)(?:[^ \t\n])' , text , re .MULTILINE )
2483+ if not ws :
2484+ return outdent , text
2485+ # Get smallest common leading indent
2486+ ws = sorted (ws )[0 ]
2487+ if len (outdent ) > len (ws ):
2488+ outdent = ws
2489+ return outdent , '' .join (
2490+ (line .replace (outdent , '' , 1 ) if line .startswith (outdent ) else line )
2491+ for line in text .splitlines (True )
2492+ )
2493+
24552494 def _uniform_indent (self , text , indent , include_empty_lines = False ):
24562495 return '' .join (
24572496 (indent + line if line .strip () or include_empty_lines else '' )
0 commit comments