Skip to content

Commit cc0f211

Browse files
authored
Fix negative heading-offsets (#271)
1 parent 577e067 commit cc0f211

File tree

5 files changed

+56
-31
lines changed

5 files changed

+56
-31
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "mkdocs-include-markdown-plugin"
3-
version = "7.1.6"
3+
version = "7.1.7"
44
description = "Mkdocs Markdown includer plugin."
55
readme = "README.md"
66
license = "Apache-2.0"

src/mkdocs_include_markdown_plugin/directive.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def parse_filename_argument(
208208

209209
def parse_string_argument(match: re.Match[str] | None) -> str | None:
210210
"""Return the string argument matched by ``match``."""
211-
if match is None:
211+
if match is None: # pragma: no cover
212212
return None
213213
value = match[1]
214214
if value is None:

src/mkdocs_include_markdown_plugin/event.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -436,27 +436,30 @@ def found_include_markdown_tag( # noqa: PLR0912, PLR0915
436436
offset_match = ARGUMENT_REGEXES['heading-offset']().search(
437437
arguments_string,
438438
)
439-
if offset_match:
440-
offset_raw_value = offset_match[1]
441-
if offset_raw_value == '':
442-
location = process.file_lineno_message(
443-
page_src_path, docs_dir, directive_lineno(),
444-
)
445-
raise PluginError(
446-
"Invalid empty 'heading-offset' argument in"
447-
f" 'include-markdown' directive at {location}",
448-
)
449-
try:
450-
offset = int(offset_raw_value)
451-
except ValueError:
452-
location = process.file_lineno_message(
453-
page_src_path, docs_dir, directive_lineno(),
454-
)
455-
raise PluginError(
456-
f"Invalid 'heading-offset' argument"
457-
f" '{offset_raw_value}' in 'include-markdown'"
458-
f" directive at {location}",
459-
) from None
439+
try:
440+
# Here None[1] would raise a TypeError
441+
offset_raw_value = offset_match[1] # type: ignore
442+
except (IndexError, TypeError): # pragma: no cover
443+
offset_raw_value = ''
444+
if offset_raw_value == '':
445+
location = process.file_lineno_message(
446+
page_src_path, docs_dir, directive_lineno(),
447+
)
448+
raise PluginError(
449+
"Invalid empty 'heading-offset' argument in"
450+
f" 'include-markdown' directive at {location}",
451+
)
452+
try:
453+
offset = int(offset_raw_value)
454+
except ValueError:
455+
location = process.file_lineno_message(
456+
page_src_path, docs_dir, directive_lineno(),
457+
)
458+
raise PluginError(
459+
f"Invalid 'heading-offset' argument"
460+
f" '{offset_raw_value}' in 'include-markdown'"
461+
f" directive at {location}",
462+
) from None
460463

461464
bool_options, invalid_bool_args = parse_bool_options(
462465
[

src/mkdocs_include_markdown_plugin/process.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
# previous to Python3.11. Also, these nested brackets can be recursive in the
3434
# Perl implementation but this doesn't seem possible in Python, the current
3535
# implementation only reaches two levels.
36-
MARKDOWN_LINK_REGEX = re.compile( # noqa: DUO138
36+
MARKDOWN_LINK_REGEX = re.compile(
3737
r'''
3838
( # wrap whole match in $1
3939
(?<!!) # don't match images - negative lookbehind
@@ -427,17 +427,19 @@ def filter_inclusions( # noqa: PLR0912
427427
def _transform_negative_offset_func_factory(
428428
offset: int,
429429
) -> Callable[[str], str]:
430-
heading_prefix = '#' * abs(offset)
430+
abs_offset = abs(offset)
431431

432432
def transform(line: str) -> str:
433433
try:
434434
if line[0] != '#':
435435
return line
436436
except IndexError: # pragma: no cover
437+
# Note for pragma: all lines include a newline
438+
# so this exception is never raised in tests.
437439
return line
438-
if line.startswith(heading_prefix):
439-
return heading_prefix + line.lstrip('#')
440-
return '#' + line.lstrip('#')
440+
stripped_line = line.lstrip('#')
441+
new_n_headings = max(len(line) - len(stripped_line) - abs_offset, 1)
442+
return '#' * new_n_headings + stripped_line
441443

442444
return transform
443445

@@ -449,11 +451,11 @@ def _transform_positive_offset_func_factory(
449451

450452
def transform(line: str) -> str:
451453
try:
452-
prefix = line[0]
454+
if line[0] != '#':
455+
return line
453456
except IndexError: # pragma: no cover
454457
return line
455-
else:
456-
return heading_prefix + line if prefix == '#' else line
458+
return heading_prefix + line
457459

458460
return transform
459461

tests/test_unit/test_include_markdown.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,26 @@
488488
[],
489489
id='heading-offset=-2',
490490
),
491+
pytest.param(
492+
'''# Header
493+
494+
{%
495+
include-markdown "{filepath}"
496+
heading-offset=-1
497+
%}
498+
''',
499+
'''#### This should be a third level heading.
500+
501+
Example data''',
502+
'''# Header
503+
504+
### This should be a third level heading.
505+
506+
Example data
507+
''',
508+
[],
509+
id='heading-offset=-1',
510+
),
491511
492512
# Markdown heading positive offset beyond rational limits
493513
pytest.param(

0 commit comments

Comments
 (0)