Skip to content

Commit 4b22fb4

Browse files
committed
Refactor pandoc Bullet and Ordered lists
1 parent 19f639d commit 4b22fb4

File tree

2 files changed

+66
-22
lines changed

2 files changed

+66
-22
lines changed

quartodoc/pandoc/blocks.py

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@
1212
from dataclasses import dataclass
1313

1414
from quartodoc.pandoc.components import Attr
15-
from quartodoc.pandoc.inlines import Inline, Inlines, InlineContent, inlinecontent_to_str
15+
from quartodoc.pandoc.inlines import (
16+
Inline,
17+
Inlines,
18+
InlineContent,
19+
inlinecontent_to_str,
20+
str_as_list_item,
21+
)
1622

1723
__all__ = (
1824
"Block",
@@ -56,14 +62,24 @@ def html(self):
5662
f"html property method not implemented for: {type(self)}"
5763
)
5864

65+
@property
66+
def as_list_item(self):
67+
"""
68+
A block as a list item
69+
70+
Some block type need special spacing consideration
71+
"""
72+
# To balance correctness, compactness and readability,
73+
# block items get an empty line between them and the next
74+
# item.
75+
return f"{self}\n\n"
76+
5977

6078
# TypeAlias declared here to avoid forward-references which
6179
# break beartype
62-
BlockContent: TypeAlias = InlineContent | Block | Sequence[Block]
6380
ContentItem: TypeAlias = str | Inline | Block
64-
DefinitionItem: TypeAlias = tuple[
65-
InlineContent, ContentItem | Sequence[BlockContent]
66-
]
81+
BlockContent: TypeAlias = ContentItem | Sequence[ContentItem]
82+
DefinitionItem: TypeAlias = tuple[InlineContent, BlockContent]
6783

6884

6985
@dataclass
@@ -79,7 +95,7 @@ def __str__(self):
7995
Div_TPL = """\
8096
::: {{{attr}}}
8197
{content}
82-
:::
98+
:::\
8399
"""
84100

85101
@dataclass
@@ -105,7 +121,7 @@ def __str__(self):
105121
# definition with more than one block.
106122
DefinitionItem_TPL = """\
107123
{term}
108-
{definitions}
124+
{definitions}\
109125
"""
110126

111127
Definition_TPL = """
@@ -167,11 +183,15 @@ class Para(Block):
167183
Paragraph
168184
"""
169185
content: Optional[InlineContent] = None
170-
171186
def __str__(self):
172187
content = inlinecontent_to_str(self.content)
173188
return f"{SEP}{content}{SEP}"
174189

190+
@property
191+
def as_list_item(self):
192+
content = inlinecontent_to_str(self.content)
193+
return f"{content}\n\n"
194+
175195

176196
@dataclass
177197
class Header(Block):
@@ -244,6 +264,9 @@ def html(self):
244264
attr = f" {self.attr.html}" if self.attr else ""
245265
return CodeBlockHTML_TPL.format(content=content, attr=attr)
246266

267+
@property
268+
def as_list_item(self):
269+
return f"\n{self}\n\n"
247270

248271

249272
@dataclass
@@ -337,8 +360,16 @@ def fmt(s:str, pfx: str):
337360
# mnop
338361
if not s:
339362
return ""
340-
pad = " " * (len(pfx) + 1)
341-
return f"{pfx} " + indent(s, pad).lstrip(pad)
363+
364+
# We avoid having a space after the item bullet/number if
365+
# there is no content on that line
366+
space = ""
367+
indent_size = len(pfx) + 1
368+
s_indented = indent(s, " " * indent_size)
369+
if s[0] != "\n":
370+
space = " "
371+
s_indented = s_indented[indent_size:]
372+
return f"{pfx}{space}{s_indented}"
342373

343374
if not content:
344375
return ""
@@ -348,18 +379,16 @@ def fmt(s:str, pfx: str):
348379
else:
349380
pfx_it = (f"{i}." for i in itertools.count(1))
350381

351-
if isinstance(content, (str, Inline, Block)):
352-
return fmt(str(content), next(pfx_it))
382+
if isinstance(content, str):
383+
return fmt(str_as_list_item(content), next(pfx_it))
384+
elif isinstance(content, (Inline, Block)):
385+
return fmt(content.as_list_item, next(pfx_it))
353386
elif isinstance(content, abc.Sequence):
354-
# To balance correctness, compactness and readability,
355-
# items with content get an empty line between them and
356-
# the next item.
357-
items = []
358-
pad = ""
359-
for item in content:
360-
s = fmt(str(item), next(pfx_it))
361-
pad = f"{SEP}{SEP}" if isinstance(item, Block) else f"{SEP}"
362-
items.append(f"{s}{pad}")
363-
return "".join(items)[:-len(pad)]
387+
it = (
388+
str_as_list_item(c) if isinstance(c, str) else c.as_list_item
389+
for c in content
390+
)
391+
items = (fmt(s, next(pfx_it)) for s in it)
392+
return "".join(items).strip()
364393
else:
365394
raise TypeError(f"Could not process type: {type(content)}")

quartodoc/pandoc/inlines.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ def html(self):
5050
f"html property method not implemented for: {type(self)}"
5151
)
5252

53+
@property
54+
def as_list_item(self):
55+
"""
56+
An inline as a list item
57+
"""
58+
return str_as_list_item(str(self))
59+
60+
5361
# TypeAlias declared here to avoid forward-references which
5462
# break beartype
5563
InlineContent: TypeAlias = str | Inline | Sequence[Inline]
@@ -230,3 +238,10 @@ def inlinecontent_to_str(content: Optional[InlineContent]):
230238
return join_inline_content(content)
231239
else:
232240
raise TypeError(f"Could not process type: {type(content)}")
241+
242+
243+
def str_as_list_item(s: str) -> str:
244+
"""
245+
How a string becomes a list item
246+
"""
247+
return f"{s}\n"

0 commit comments

Comments
 (0)