Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ bullets
lists are nested. Otherwise, the bullet will alternate based on nesting
level. Defaults to ``'*+-'``.

list_indent_width
Minimum width, in spaces, of a list item's marker and following whitespace.
Defaults to ``0``, which uses the marker's natural width. Set to ``4`` to
preserve nested lists when the output is parsed by Python-Markdown.
Extra spaces are added after the marker, and continuation lines use the
same indentation. Markers wider than this minimum are never truncated.
Available as ``--list-indent-width`` on the command line.

strong_em_symbol
In markdown, both ``*`` and ``_`` are used to encode **strong** or
*emphasized* texts. Either of these symbols can be chosen by the options
Expand Down
4 changes: 3 additions & 1 deletion markdownify/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ class DefaultOptions:
escape_misc = False
heading_style = UNDERLINED
keep_inline_images_in = []
list_indent_width = 0
newline_style = SPACES
strip = None
strip_document = STRIP
Expand Down Expand Up @@ -647,7 +648,8 @@ def convert_li(self, el, text, parent_tags):
el = el.parent
bullets = self.options['bullets']
bullet = bullets[depth % len(bullets)]
bullet = bullet + ' '
# Pad the marker and continuation lines to the requested minimum width.
bullet = (bullet + ' ').ljust(self.options['list_indent_width'])
bullet_width = len(bullet)
bullet_indent = ' ' * bullet_width

Expand Down
2 changes: 2 additions & 0 deletions markdownify/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def markdownify(
escape_misc: bool = ...,
heading_style: str = ...,
keep_inline_images_in: list[str] = ...,
list_indent_width: int = ...,
newline_style: str = ...,
strip: Union[list[str], None] = ...,
strip_document: Union[str, None] = ...,
Expand Down Expand Up @@ -57,6 +58,7 @@ class MarkdownConverter:
escape_misc: bool = ...,
heading_style: str = ...,
keep_inline_images_in: list[str] = ...,
list_indent_width: int = ...,
newline_style: str = ...,
strip: Union[list[str], None] = ...,
strip_document: Union[str, None] = ...,
Expand Down
3 changes: 3 additions & 0 deletions markdownify/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ def main(argv=sys.argv[1:]):
parser.add_argument('-b', '--bullets', default='*+-',
help="A string of bullet styles to use; the bullet will "
"alternate based on nesting level.")
parser.add_argument('--list-indent-width', type=int, default=0,
help="Minimum list item indentation. Use 4 for compatibility "
"with Python-Markdown; 0 uses the marker width.")
parser.add_argument('--strong-em-symbol', default=ASTERISK,
choices=(ASTERISK, UNDERSCORE),
help="Use * or _ to convert strong and italics text"),
Expand Down
41 changes: 41 additions & 0 deletions tests/test_lists.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import subprocess
import sys

import pytest

from .utils import md


Expand Down Expand Up @@ -87,3 +92,39 @@ def test_bullets():

def test_li_text():
assert md('<ul><li>foo <a href="#">bar</a></li><li>foo bar </li><li>foo <b>bar</b> <i>space</i>.</ul>') == '\n\n* foo [bar](#)\n* foo bar\n* foo **bar** *space*.\n'


@pytest.mark.parametrize('html, expected', [
('<ul><li>a<ul><li>b<ul><li>c<ul><li>d</li></ul></li></ul></li></ul></li></ul>',
'\n\n* a\n + b\n - c\n * d\n'),
('<ol><li>a<ol><li>b<ol><li>c<ol><li>d</li></ol></li></ol></li></ol></li></ol>',
'\n\n1. a\n 1. b\n 1. c\n 1. d\n'),
('<ul><li><p>first</p><p>second</p><blockquote>quote</blockquote></li></ul>',
'\n\n* first\n\n second\n\n > quote\n'),
('<ul><li>a<ol><li>b</li></ol></li><li>c</li></ul>',
'\n\n* a\n 1. b\n* c\n'),
('<ol start="1234"><li><p>first</p><p>second</p></li></ol>',
'\n\n1234. first\n\n second\n'),
])
def test_list_indent_width(html, expected):
assert md(html, list_indent_width=4) == expected


def test_list_indent_width_minimum():
html = '<ol start="10"><li>a<ul><li>b</li></ul></li></ol>'
assert md(html, list_indent_width=0) == md(html)
assert md(html, list_indent_width=1) == md(html)


@pytest.mark.parametrize('use_file', [False, True])
def test_list_indent_width_cli(tmp_path, use_file):
html = '<ul><li>a<ul><li>b</li></ul></li></ul>'
command = [sys.executable, '-m', 'markdownify.main', '--list-indent-width', '4']
if use_file:
path = tmp_path / 'nested.html'
path.write_text(html, encoding='utf-8')
command.append(str(path))
result = subprocess.run(command, input='' if use_file else html,
text=True, capture_output=True)
assert result.returncode == 0, result.stderr
assert result.stdout == '* a\n + b\n'
3 changes: 3 additions & 0 deletions tests/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
escape_misc=False,
heading_style=UNDERLINED,
keep_inline_images_in=[],
list_indent_width=0,
newline_style=SPACES,
strip=None,
strip_document=STRIP,
Expand All @@ -47,6 +48,7 @@
sup_symbol='^',
sub_symbol='^',
keep_inline_images_in=['h3'],
list_indent_width=4,
wrap=True,
wrap_width=80,
strong_em_symbol=UNDERSCORE,
Expand All @@ -68,3 +70,4 @@ def callback(el: BeautifulSoup) -> Union[str, None]:

markdownify('<pre class="python">test\n foo\nbar</pre>', code_language_callback=callback)
markdownify('<pre class="python">test\n foo\nbar</pre>', code_language_callback=lambda el: None)
markdownify('<ul><li>item</li></ul>', list_indent_width=4)