diff --git a/src/urwidgets/hyperlink.py b/src/urwidgets/hyperlink.py index ec41eed..3dc437f 100644 --- a/src/urwidgets/hyperlink.py +++ b/src/urwidgets/hyperlink.py @@ -57,6 +57,33 @@ class Hyperlink(urwid.WidgetWrap): separate by any terminal emulator that correctly implements the feature. Also, if a hyperlink is wrapped or clipped, it shouldn't break. + .. collapse:: Examples: + + >>> from urwidgets import Hyperlink + >>> + >>> url = "https://urwid.org" + >>> + >>> # The hyperlinks in the outputs should be highlighted on mouse hover + >>> # and clickable (in the terminal), if supported. + >>> + >>> # Raw URI + >>> link = Hyperlink(url) + >>> canv = link.render(len(url)) + >>> print(canv.text[0].decode()) + https://urwid.org + >>> + >>> # Clipped (with an ellipsis appended) when the render width (maxcols) is + >>> # shorter than the link text + >>> canv = link.render(len(url) - 4) + >>> print(canv.text[0].decode()) + https://urwid… + >>> + >>> # URI with custom text + >>> hyperlink = Hyperlink(url, text="Urwid Website") + >>> canv = hyperlink.render(hyperlink.pack()[:1]) + >>> print(canv.text[0].decode()) + Urwid Website + .. seealso:: - `OSC 8 Specification `_ diff --git a/src/urwidgets/text_embed.py b/src/urwidgets/text_embed.py index d0add40..ebef9f6 100644 --- a/src/urwidgets/text_embed.py +++ b/src/urwidgets/text_embed.py @@ -59,18 +59,18 @@ class TextEmbed(urwid.Text): display attribute**, where the display attribute is the number of screen columns the widget should occupy. - Examples: - - >>> # w1 spans 2 columns - >>> TextEmbed(["This widget (", (2, w1), ") spans two columns"]) - >>> # w1 and w2 span 2 columns - >>> TextEmbed(["These widgets (", (2, [w1, w2]), ") span two columns each"]) - >>> # w1 and w2 span 2 columns, the text in-between has no display attribute - >>> TextEmbed([(2, [w1, (None, "and"), w2]), " span two columns each"]) - >>> # w1 and w2 span 2 columns, text in the middle is red - >>> TextEmbed((2, [w1, ("red", " i am red "), w2])) - >>> # w1 and w3 span 2 columns, w2 spans 5 columns - >>> TextEmbed((2, [w1, (5, w2), w3])) + .. collapse:: Examples: + + >>> # w1 spans 2 columns + >>> TextEmbed(["This widget (", (2, w1), ") spans two columns"]) + >>> # w1 and w2 span 2 columns + >>> TextEmbed(["These widgets (", (2, [w1, w2]), ") span two columns each"]) + >>> # w1 and w2 span 2 columns, the text in-between has no display attribute + >>> TextEmbed([(2, [w1, (None, "and"), w2]), " span two columns each"]) + >>> # w1 and w2 span 2 columns, text in the middle is red + >>> TextEmbed((2, [w1, ("red", " i am red "), w2])) + >>> # w1 and w3 span 2 columns, w2 spans 5 columns + >>> TextEmbed((2, [w1, (5, w2), w3])) Visible embedded widgets are always rendered (may be cached) whenever the ``TextEmbed`` widget is re-rendered (i.e an uncached render). Hence, this @@ -94,6 +94,31 @@ class TextEmbed(urwid.Text): TypeError: A widget markup element has a non-integer display attribute. ValueError: A widget doesn't support box sizing. ValueError: A widget has a non-positive width (display attribute). + + .. collapse:: Example: + + >>> from urwidgets import TextEmbed, Hyperlink + >>> from urwid import Filler + >>> + >>> url = "https://urwid.org" + >>> this = Hyperlink(url, text="This") + >>> link = Hyperlink(url) + >>> + >>> text_embed = TextEmbed( + ... [ + ... (4, Filler(this)), + ... " is a ", + ... ("bold", "link"), + ... " to ", + ... (len(url), Filler(link)), + ... ] + ... ) + >>> + >>> canv = text_embed.render(text_embed.pack()[:1]) + >>> # The hyperlinks (`This` and `https://urwid.org`) should be highlighted + >>> # on mouse hover and clickable (in the terminal), if supported. + >>> print(canv.text[0].decode()) + This is a link to https://urwid.org """ PLACEHOLDER_HEAD: ClassVar[str] = "\uf8fe" @@ -508,45 +533,45 @@ def parse_text( value returned is *false* (such as ``None`` or an empty string), it is omitted from the result. - Example:: - - import re - from urwid import Filler - from urwidgets import Hyperlink, TextEmbed, parse_text - - MARKDOWN = { - re.compile(r"\*\*(.+?)\*\*"): lambda g: ("bold", g[1]), - re.compile("https://[^ ]+"): ( - lambda g: (min(len(g[0]), 14), Filler(Hyperlink(g[0], "blue"))) - ), - re.compile(r"\[(.+)\]\((.+)\)"): ( - lambda g: (len(g[1]), Filler(Hyperlink(g[2], "blue", g[1]))) - ), - } - - link = "https://urwid.org" - text = f"[This]({link}) is a **link** to {link}" - print(text) - # Output: [This](https://urwid.org) is a **link** to https://urwid.org - - markup = parse_text( - text, MARKDOWN, lambda pattern, groups, span: MARKDOWN[pattern](groups) - ) - print(markup) - # Output: - # [ - # (4, >), - # ' is a ', - # ('bold', 'link'), - # ' to ', - # (14, >), - # ] - - text_widget = TextEmbed(markup) - canv = text_widget.render(text_widget.pack()[:1]) - print(canv.text[0].decode()) - # Output: This is a link to https://urwid… - # The hyperlinks will be clickable if supported + .. collapse:: Example: + + >>> import re + >>> from urwid import Filler + >>> from urwidgets import Hyperlink, TextEmbed, parse_text + >>> + >>> MARKDOWN = { + >>> re.compile(r"\*\*(.+?)\*\*"): lambda g: ("bold", g[1]), + >>> re.compile("https://[^ ]+"): ( + >>> lambda g: (len(g[0]), Filler(Hyperlink(g[0]))) + >>> ), + >>> re.compile(r"\[(.+)\]\((.+)\)"): ( + >>> lambda g: (len(g[1]), Filler(Hyperlink(g[2], text=g[1]))) + >>> ), + >>> } + >>> + >>> link = "https://urwid.org" + >>> text = f"[This]({link}) is a **link** to {link}" + >>> print(text) + [This](https://urwid.org) is a **link** to https://urwid.org + >>> + >>> markup = parse_text( + >>> text, MARKDOWN, lambda pattern, groups, span: MARKDOWN[pattern](groups) + >>> ) + >>> print(markup) + [ + (4, >), + ' is a ', + ('bold', 'link'), + ' to ', + (17, >), + ] + >>> + >>> text_widget = TextEmbed(markup) + >>> canv = text_widget.render(text_widget.pack()[:1]) + >>> # The hyperlinks (`This` and `https://urwid.org`) should be highlighted + >>> # on mouse hover and clickable (in the terminal), if supported. + >>> print(canv.text[0].decode()) + This is a link to https://urwid.org NOTE: In the case of overlapping matches, the substring that occurs first is matched