metalines: use a 3-uple instead of dict

exec
dece 3 years ago
parent 016e4a49f9
commit f7b4607ed6

@ -552,19 +552,19 @@ class Browser:
line_pos = y + py
if line_pos >= len(self.current_page.metalines):
return
meta, line = self.current_page.metalines[line_pos]
if meta["type"] != LineType.LINK:
ltype, ltext, lextra = self.current_page.metalines[line_pos]
if ltype != LineType.LINK:
return
# "url" key is contained only in the first line of the link if its text
# is wrapped, so if the user did not click on the first line, rewind to
# get the URL.
while "url" not in meta:
while not lextra or "url" not in lextra:
line_pos -= 1
meta, line = self.current_page.metalines[line_pos]
url = meta["url"]
_, ltext, lextra = self.current_page.metalines[line_pos]
url = lextra["url"]
# The click is valid if it is on the link itself or the dimmed preview.
col_pos = x + px
if col_pos > len(line):
if col_pos > len(ltext):
ch = self.page_pad.pad.instr(line_pos, col_pos, 1)
if ch == b' ':
return
@ -834,8 +834,8 @@ class Browser:
if not search:
return
self.search_res_lines = []
for index, (_, line) in enumerate(self.current_page.metalines):
if search in line:
for index, (_, ltext, _) in enumerate(self.current_page.metalines):
if search in ltext:
self.search_res_lines.append(index)
if self.search_res_lines:
self.move_to_search_result(Browser.SEARCH_NEXT)

@ -6,6 +6,18 @@ displayed, along with associated meta-data such as its type or a link's URL.
Note that metalines can be generated by custom functions without relying on the
elements classes as they are quite coupled to Gemtext parsing/rendering.
The metalines are tuples (ltype, line, lextra):
- ltype is the LineType.
- line is the text content itself.
- lextra is either a dict of additional data, or None.
The lextra part is currently only used for links, and can contain the following
keys:
- url: 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. long link descriptions wrapped on
multiple lines will not have a this key except for the first line.
- link_id: only alongside "url" key, ID generated for this link.
"""
import string
@ -53,22 +65,12 @@ class RenderOptions:
def generate_metalines(elements: list, options: RenderOptions) -> list:
"""Format elements into a list of lines with metadata.
The returned list ("metalines") are tuples (meta, line), meta being a
dict of metadata and a text line to display. Currently the only metadata
keys used are:
- type: one of the Renderer.TYPE constants.
- 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.
long link descriptions wrapped on multiple lines will not have a this
key except for the first line.
- link_id: only alongside "url" key, ID generated for this link.
Arguments:
- elements: list of elements to use.
- options: RenderOptions to respect when generating metalines.
"""
metalines = []
separator = ({"type": LineType.NONE}, "")
separator = (LineType.NONE, "", None)
has_margins = False
thin_type = None
for index, element in enumerate(elements):
@ -100,7 +102,7 @@ def generate_metalines(elements: list, options: RenderOptions) -> list:
# rendered as empty lines.
if options.mode == "dumb":
if not element_metalines:
element_metalines = [({"type": LineType.PARAGRAPH}, "")]
element_metalines = [(LineType.PARAGRAPH, "", None)]
# If current element requires margins and is not the first elements,
# 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
@ -119,7 +121,7 @@ def generate_metalines(elements: list, options: RenderOptions) -> list:
def generate_dumb_metalines(lines):
"""Generate dumb metalines: all lines are given the PARAGRAPH line type."""
return [({"type": LineType.PARAGRAPH}, line) for line in lines]
return [(LineType.PARAGRAPH, line, None) for line in lines]
def format_title(title: Title, options: RenderOptions):
@ -135,13 +137,13 @@ def format_title(title: Title, options: RenderOptions):
else:
lines = wrap_words(title.text, width)
# Title levels match the type constants of titles.
return [({"type": LineType(title.level)}, line) for line in lines]
return [(LineType(title.level), line, None) for line in lines]
def format_paragraph(paragraph: Paragraph, options: RenderOptions):
"""Return metalines for this paragraph."""
lines = wrap_words(paragraph.text, options.width)
return [({"type": LineType.PARAGRAPH}, line) for line in lines]
return [(LineType.PARAGRAPH, line, None) for line in lines]
def format_link(link: Link, options: RenderOptions):
@ -151,30 +153,26 @@ def format_link(link: Link, options: RenderOptions):
link_text = link.text or link.url
# Wrap lines, indented by the link anchor length.
lines = wrap_words(link_text, options.width, indent=len(link_anchor))
first_line_meta = {
"type": LineType.LINK,
first_line_extra = {
"url": link.url,
"link_id": link.ident
}
# Replace first line indentation with the anchor.
first_line_text = link_anchor + lines[0][len(link_anchor):]
first_line = [(first_line_meta, first_line_text)]
other_lines = [({"type": LineType.LINK}, line) for line in lines[1:]]
return first_line + other_lines
first_line = [(LineType.LINK, first_line_text, first_line_extra)]
other_lines = [(LineType.LINK, line, None) for line in lines[1:]]
return first_line + other_lines # type: ignore
def format_preformatted(preformatted: Preformatted, options: RenderOptions):
"""Return metalines for this preformatted block."""
return [
({"type": LineType.PREFORMATTED}, line)
for line in preformatted.lines
]
return [(LineType.PREFORMATTED, line, None) for line in preformatted.lines]
def format_blockquote(blockquote: Blockquote, options: RenderOptions):
"""Return metalines for this blockquote."""
lines = wrap_words(blockquote.text, options.width, indent=2)
return [({"type": LineType.BLOCKQUOTE}, line) for line in lines]
return [(LineType.BLOCKQUOTE, line, None) for line in lines]
def format_list_item(item: ListItem, options: RenderOptions):
@ -183,7 +181,7 @@ def format_list_item(item: ListItem, options: RenderOptions):
lines = wrap_words(item.text, options.width, indent=indent)
first_line = options.bullet + lines[0][indent:]
lines[0] = first_line
return [({"type": LineType.LIST_ITEM}, line) for line in lines]
return [(LineType.LIST_ITEM, line, None) for line in lines]
def wrap_words(text: str, width: int, indent: int =0) -> List[str]:

@ -37,13 +37,12 @@ def render_lines(metalines, window, max_width):
def render_line(metaline, window, max_width):
"""Write a single line to the window."""
meta, line = metaline
line_type = meta["type"]
attributes = get_base_line_attributes(line_type)
line = line[:max_width - 1]
ltype, ltext, lextra = metaline
attributes = get_base_line_attributes(ltype)
line = ltext[:max_width - 1]
window.addstr(line, attributes)
if meta["type"] == LineType.LINK and "url" in meta:
url_text = f' {meta["url"]}'
if ltype == LineType.LINK and lextra and "url" in lextra:
url_text = f' {lextra["url"]}'
attributes = (
curses.color_pair(ColorPair.LINK_PREVIEW)
| curses.A_DIM

Loading…
Cancel
Save