page: add a dumb rendering mode

Dumb mode affects Gemtext parsing (gotta keep those empty lines) and
rendering (render empty lines, do not attempt to put smart margins).
This commit is contained in:
dece 2021-05-28 13:34:08 +02:00
parent 46ec9879e6
commit 1468e6ef10
3 changed files with 21 additions and 9 deletions

View file

@ -54,7 +54,7 @@ class ListItem:
ParsedGemtext = namedtuple("ParsedGemtext", ("elements", "links", "title")) ParsedGemtext = namedtuple("ParsedGemtext", ("elements", "links", "title"))
def parse_gemtext(text: str) -> ParsedGemtext: def parse_gemtext(text: str, dumb=False) -> ParsedGemtext:
"""Parse a string of Gemtext into a list of elements.""" """Parse a string of Gemtext into a list of elements."""
elements = [] elements = []
links = Links() links = Links()
@ -63,7 +63,9 @@ def parse_gemtext(text: str) -> ParsedGemtext:
preformatted = None preformatted = None
for line in text.splitlines(): for line in text.splitlines():
line = line.rstrip() line = line.rstrip()
if not line: # In standard mode, discard empty lines. In dumb mode, empty lines are
# kept as basic text.
if not line and not dumb:
continue continue
if line.startswith(Preformatted.FENCE): if line.startswith(Preformatted.FENCE):

View file

@ -35,18 +35,23 @@ class LineType(IntEnum):
LIST_ITEM = 8 LIST_ITEM = 8
def generate_metalines(elements, width): def generate_metalines(elements, width, dumb=False):
"""Format elements into a list of lines with metadata. """Format elements into a list of lines with metadata.
The returned list ("metalines") are tuples (meta, line), meta being a The returned list ("metalines") are tuples (meta, line), meta being a
dict of metadata and line a text line to display. Currently the only dict of metadata and a text line to display. Currently the only metadata
metadata keys used are: keys used are:
- type: one of the Renderer.TYPE constants. - type: one of the Renderer.TYPE constants.
- url: only for links, the URL the link on this line refers to. Note - url: only for links, the URL the link on this line refers to. Note
that this key is present only for the first line of the link, i.e. that this key is present only for the first line of the link, i.e.
long link descriptions wrapped on multiple lines will not have a this long link descriptions wrapped on multiple lines will not have a this
key except for the first line. key except for the first line.
- link_id: only alongside "url" key, ID generated for this link. - link_id: only alongside "url" key, ID generated for this link.
Arguments:
- elements: list of elements to use.
- width: max text width to use.
- dumb: if True, standard presentation margins are ignored.
""" """
metalines = [] metalines = []
context = {"width": width} context = {"width": width}
@ -78,12 +83,17 @@ def generate_metalines(elements, width):
thin_type = LineType.LIST_ITEM thin_type = LineType.LIST_ITEM
else: else:
continue continue
# In dumb mode, elements producing no metalines still need to be
# rendered as empty lines.
if dumb:
if not element_metalines:
element_metalines = [({"type": LineType.PARAGRAPH}, "")]
# If current element requires margins and is not the first elements, # If current element requires margins and is not the first elements,
# separate from previous element. Also do it if the current element does # separate from previous element. Also do it if the current element does
# not require margins but follows an element that required it (e.g. link # not require margins but follows an element that required it (e.g. link
# after a paragraph). Also do it if both the current and previous # after a paragraph). Also do it if both the current and previous
# elements do not require margins but differ in type. # elements do not require margins but differ in type.
if ( elif (
(has_margins and index > 0) (has_margins and index > 0)
or (not has_margins and previous_had_margins) or (not has_margins and previous_had_margins)
or (not has_margins and thin_type != last_thin_type) or (not has_margins and thin_type != last_thin_type)

View file

@ -28,10 +28,10 @@ class Page:
encoding: str = "" encoding: str = ""
@staticmethod @staticmethod
def from_gemtext(gemtext: str, wrap_at: int): def from_gemtext(gemtext: str, wrap_at: int, dumb: bool =False):
"""Produce a Page from a Gemtext file or string.""" """Produce a Page from a Gemtext file or string."""
elements, links, title = parse_gemtext(gemtext) elements, links, title = parse_gemtext(gemtext, dumb=dumb)
metalines = generate_metalines(elements, wrap_at) metalines = generate_metalines(elements, wrap_at, dumb=dumb)
return Page(gemtext, metalines, links, title) return Page(gemtext, metalines, links, title)
@staticmethod @staticmethod