API Reference#

Attention

đźš§ There might be incompatible changes between minor versions of version zero!

If you want to use this library in a project while it’s still on version zero, ensure you pin the dependency to a specific minor version e.g >=0.1,<0.2.

urWIDgets

A collection of widgets for urwid (https://urwid.org)

Functions:

parse_text

Parses a string into a text/widget markup.

Classes:

Hyperlink

A widget containing hyperlinked text.

TextEmbed

A text widget within which other widgets may be embedded.

urwidgets.parse_text(text, patterns, repl, *repl_args, **repl_kwargs)[source]#

Parses a string into a text/widget markup.

Parameters:
  • text (str) – The string to parse.

  • patterns (Iterable[re.Pattern]) – An iterable of RegEx pattern objects.

  • repl (Callable[[re.Pattern, Tuple[str | None], Tuple[int, int], ...], Markup]) – A callable to replace a substring of text matched by any of the given RegEx patterns.

  • repl_args (Any) – Additional positional arguments to be passed to repl whenever it’s called.

  • repl_kwargs (Any) – keyword arguments to be passed to repl whenever it’s called.

Returns:

A text/widget markup (see Markup) that should be compatible with TextEmbed and/or urwid.Text, depending on the values returned by repl.

Raises:
  • TypeError – An argument is of an unexpected type.

  • ValueError – patterns is empty.

  • ValueError – A given pattern object was not compiled from a str instance.

Return type:

Markup

Whenever any of the given RegEx patterns matches a non-empty substring of text, repl is called with the following arguments (in the given order):

  • the Pattern object that matched the substring

  • a tuple containing the match groups

    • starting with the whole match,

    • followed by the all the subgroups of the match, from 1 up to however many groups are in the pattern, if any (None for each group that didn’t participate in the match)

  • a tuple containing the span (start and end indexes) of the substring

  • repl_args unpacked

  • repl_kwargs unpacked

and should return a valid text/widget markup (see Markup). If the 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: (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, <Filler box widget <Hyperlink flow widget>>),
  ' is a ',
  ('bold', 'link'),
  ' to ',
  (17, <Filler box widget <Hyperlink flow widget>>),
]
>>>
>>> text_widget = TextEmbed(markup)
>>> canv = text_widget.render(())
>>> # 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 and if they start at the same index, the pattern that appears first in patterns takes precedence.

Bases: urwid.widget.widget.WidgetWrap

A widget containing hyperlinked text.

Parameters:
  • uri (str) –

    The target of the hyperlink in URI (Uniform Resource Identifier)-encoded form.

    May be a web address (http://... or https://...), FTP address (ftp://...), local file (file://...), e-mail address (mailto:), etc.

    Every byte of this string, after being encoded, must be within the range 32 to 126 (both inclusive).

  • attr (DisplayAttribute) – Display attribute of the hyperlink text.

  • text (Optional[str]) – Alternative hyperlink text. If not given or None, the URI itself is used. Must be a single-line string.

Raises:
  • TypeError – An argument is of an unexpected type.

  • ValueError – An argument is of an expected type but of an unexpected value

This widget always renders a single line, with left alignment and the ellipsis wrap mode of urwid.Text i.e if the widget is rendered with a width less than the length of the hyperlink text, it is clipped at the right end with an ellipsis appended; on the other hand, if rendered with a width greater, it is padded with spaces on the right end.

This widget is intended to be embedded in a TextEmbed widget to combine it with pure text or other widgets but may as well be used otherwise.

This widget utilizes the OSC 8 escape sequence implemented by a sizable number of mainstream terminal emulators. It utilizes the escape sequence in such a way that hyperlinks right next to one another should be detected, highlighted and treated as separate by any terminal emulator that correctly implements the feature. Also, if a hyperlink is wrapped or clipped, it shouldn’t break.

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(())
>>> 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(())
>>> print(canv.text[0].decode())
Urwid Website

See also

OSC 8 Specification

Official specification for hyperlinks in terminals.

OSC 8 adoption in terminal emulators

Documentation of the adoption of the feature across terminal emulators and terminal-based applications.

TextEmbed

A widget that enables the use of hyperlinks amidst normal text.

Attributes:

attrib

The display attirbute of the hyperlink.

text

The alternate text of the hyperlink.

uri

The target of the hyperlink.

property attrib#

The display attirbute of the hyperlink.

Type:

DisplayAttribute

GET:

Returns the display attirbute.

SET:

Sets the display attirbute.

property text#

The alternate text of the hyperlink.

Type:

str

GET:

Returns the alternate text.

SET:

Sets the alternate text.

property uri#

The target of the hyperlink.

Type:

str

GET:

Returns the target.

SET:

Sets the target.

class urwidgets.TextEmbed(markup, align=Align.LEFT, wrap=WrapMode.SPACE, layout=None)[source]#

Bases: urwid.widget.text.Text

A text widget within which other widgets may be embedded.

This is an extension of the urwid.Text widget. Every feature and interface of Text is supported and works essentially the same, except for the “ellipsis” wrap mode which is currently not implemented. Text markup format is essentially the same, except when embedding widgets.

Embedding Widgets

A widget is embedded by specifying it as a markup element with an integer 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]))

Visible embedded widgets are always rendered (may be cached) whenever the TextEmbed widget is re-rendered (i.e an uncached render). Hence, this allows for dynamic parts of text without updating the entire widget. Going a step further, embeddded widgets can be swapped using urwid.WidgetPlaceholder but their widths will remain the same.

Note

  • Every embedded widget must be a box widget and is always rendered with size (width, 1). urwid.Filler can be used to wrap flow widgets.

  • As regards the “space” wrap mode, each embedded widget is treated as a single WORD (i.e containing no whitespace). In other words, whitespace within embedded widgets do not influence wrapping.

  • After updating or swapping an embedded widget, the containing TextEmbed widget’s canvases should be invalidated to ensure it re-renders.

Raises:
  • 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).

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(())
>>> # 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

See also

parse_text()

Parses a string into a text/widget markup that can be used with this class.

Attributes:

PLACEHOLDER_HEAD

PLACEHOLDER_TAIL

Embedded widgets' text placeholder components.

attrib

Run-length encoding of display attributes of the widget's content.

embedded

Embedded widgets.

text

Raw text content of the widget.

Methods:

get_text

Returns a representation of the widget's content.

set_text

Sets the widget's content.

PLACEHOLDER_HEAD: ClassVar[str] = '\uf8fe'#
PLACEHOLDER_TAIL: ClassVar[str] = '\uf8ff'#

Embedded widgets’ text placeholder components.

Each should be a unique unicode codepoint that:

  • occupies exactly one column on a terminal screen.

  • is guaranteed to not occur in the text content of the widget, if any.

Either or both may only be overriden on subclasses (during their creation, not after), as in:

class TextEmbedSub(TextEmbed):
    PLACEHOLDER_HEAD = "="
    PLACEHOLDER_TAIL = "-"

Note

In most cases, the defaults should be sufficient. There’s no need to override these except it’s possible for the default values to occur in the widget’s text content (if any), which is highly unlikely.

That said, the default values should be considered implementation detail; hence, may change at any time without notice. They’re only provided to help the user avoid conflicts with actual text content. If the values are depended upon, then they should be overriden on a subclass, as described above.

property attrib#

Run-length encoding of display attributes of the widget’s content.

Type:

List[Tuple[Union[DisplayAttribute, int], int]]

See the description of the second item in the return value of get_text().

property embedded#

Embedded widgets.

Returns:

A list of all embedded widgets and their respective widths, in the same order in which they were given in the text markup.

Type:

List[Tuple[urwid.Widget, int]]

property text#

Raw text content of the widget.

Type:

str

See the description of the first item in the return value of get_text().

get_text()[source]#

Returns a representation of the widget’s content.

Returns:

A tuple (text, attrib), where

  • text is the raw text content of the widget.

    Each embedded widget is represented by a placeholder substring with length equal to the widget’s width.

  • attrib is the run-length encoding of display attributes.

    Any entry containing a display attribute of the int type (e.g (1, 4)) denotes an embedded widget, where the display attirbute is the index of the widget within the embedded widgets list and the run length is the width of the widget.

Return type:

Tuple[str, List[Tuple[DisplayAttribute | int, int]]]

set_text(markup)[source]#

Sets the widget’s content.

Also supports widget markup elements. See the class description.

Type Aliases#

Important

These may not be complete or correct for use with a static type checker. They’re intended for the comprehension of interfaces defined in this package, by programmers.

urwidgets.Markup(*args, **kwargs)#

alias of Union[StringMarkup, ListMarkup, TupleMarkup]

urwidgets.StringMarkup(*args, **kwargs)#

alias of Union[str, bytes]

urwidgets.ListMarkup(*args, **kwargs)#

alias of List[Markup]

urwidgets.TupleMarkup(*args, **kwargs)#

alias of Union[NormalTupleMarkup, WidgetTupleMarkup]

urwidgets.NormalTupleMarkup(*args, **kwargs)#

alias of Tuple[DisplayAttribute, Union[StringMarkup, ListMarkup]]

urwidgets.DisplayAttribute(*args, **kwargs)#

alias of Union[None, str, bytes, urwid.AttrSpec]

urwidgets.WidgetTupleMarkup(*args, **kwargs)#

alias of Tuple[int, Union[urwid.Widget, WidgetListMarkup]]

urwidgets.WidgetListMarkup(*args, **kwargs)#

alias of List[Union[urwid.Widget, Markup, WidgetListMarkup]]