Skip to content

Print formatted text

The BLISS shell provides different way to print formatted text.

Note

Usage of styles is a manner to keep readable colors on dark and light terminals.

The easiest way to print colors is to use print_html() with a HTML-like formatting. It supports some common tags, and few others for colors.

Note

This print_html() function is available only in a Bliss shell.

Most colors are intented to be abstract in order to be picked according to the environement. Right now it is selected according to the dark/light mode of the background. But it could be selected according to the used style, the beamline or the session.

That is one of the recommended way to add colors, in order to provide a more consistent UI. This also can be tuned globally if needed.

Common tags

from bliss.shell.standard import print_html

print_html("""
<h1>My title</h1>
   <h2>My title</h2>
      <h3>My title</h3>
You can use the mark tag to <mark>highlight</mark> text.
<del>This line of text is meant to be treated as deleted text.</del>
<s>This line of text is meant to be treated as no longer accurate.</s>
<ins>This line of text is meant to be treated as an addition to the document.</ins>
<u>This line of text will render as underlined.</u>
<small>This line of text is meant to be treated as fine print.</small>
<strong>This line rendered as bold text.</strong>
<em>This line rendered as italicized text.</em>
""")

Screenshot

Color palette tags

Few abstract colors are defined if you want to identify different elements. It’s a set of color from a consistent palette.

print_html("""
 <color1>It's the color1</color1>
 <color2>It's the color2</color2>
 <color3>It's the color3</color3>
 <color4>It's the color4</color4>
 <color5>It's the color5</color5>
 <color6>It's the color6</color6>
""")

Screenshot

For now this palette reuses the one defined for the standard terminal. But this could change in the future.

Warning tags

Some tags for warnings are also available. The name was reused from the Bootstrap library.

print_html("""
<info>Info color</info>
<success>Success color</success>
<warning>Warning color</warning>
<danger>Danger color</danger>
<fatal>Fatal color</fatal>

<bg-info> Info colors      </bg-info>
<bg-success> Success colors   </bg-success>
<bg-warning> Warning colors   </bg-warning>
<bg-danger> Danger colors    </bg-danger>
<bg-fatal> Fatal colors     </bg-fatal>
""")

Screenshot

Fixed color tags

Note

Fixed color tags are not recommended.

If needed, fixed colors can be used the following way.

# Colors from the ANSI palette.
print_html("<ansired>This is red</ansired>")
print_html("<ansigreen>This is green</ansigreen>")
# Named colors (256 color palette, or true color, depending on the output).
print_html("<skyblue>This is sky blue</skyblue>")
print_html("<seagreen>This is sea green</seagreen>")
print_html("<violet>This is violet</violet>")

Both foreground and background colors can also be specified setting the fg and bg attributes of any HTML tag:

print_html("<aaa fg='ansiwhite' bg='ansigreen'>White on green</aaa>")

The color attributes can also be specified using hexadecial HTML color.

print_html("<aaa fg='#FF0000' bg='#404040'>Red on grey</aaa>")

Note

ANSI colors tags are not recommended.

A dedicated print is provided to display colors with ANSI sequence.

It can be used together with color helper.

It is mostly here for compatibility, and still have maybe use cases.

from bliss.shell.formatters.ansi import PURPLE, CYAN, DARKCYAN, BLUE, GREEN, YELLOW, RED, UNDERLINE, BOLD

print_ansi(RED("Abort !!!"))
  • PURPLE(msg)
  • CYAN(msg)
  • DARKCYAN(msg)
  • BLUE(msg)
  • GREEN(msg)
  • YELLOW(msg)
  • RED(msg)
  • UNDERLINE(msg)
  • BOLD(msg)

Tables

A common library to display table is tabulate. Unfortunatly it does not support style.

A simplified version was designed to support styles.

It can be used the following way:

from bliss.shell.formatters import tabulate
print(tabulate.tabulate([
    [("class:header", "axis"), ("class:header", "position"), ("class:header", "unit")],
    [robx.name, ("class:warning", robx.position), robx.unit],
    [roby.name, ("class:color1", roby.position), roby.unit]
]))

You could want to display in the shell the content of something that can be updated or displayed until a manual abort.

We provide a text_block() helper for that.

It ansure to properly handle a user abort (CTRL-C) and that the display will not be broken by other print or logging. For that every use of print() or logging module will be displayed above this context.

Follow a processing

Here we change the displayed content between some processing.

with text_block() as tb:
    tb.set_text("Prepare processing")
    sleep(2)  # do stuff
    tb.set_text("Processing...")
    sleep(5)  # do stuff
    tb.set_text("Processing done")

Programatic rendering

Instead of explicitly tell what to display, a callback can be defined. This callback will be called everytime the block have to be redisplayed (commonly 3 times every seconds).

import time

start_time = time.time()

def render():
    # User function which returns height and content
    import time
    return 1, f" {time.time() - start_time:.2f} s"

with text_block(render):
    # wait forever
    while True:
        sleep(1)

Screenshot

Notice that it displays for you a toolbar to remember to use CTRL-C to abort.

In this case it raises a KeyboardInterrupt which can be captured by you if you need.

Feedback on error

The next step to setup this TextBlockApplication is to use a processing which have to be monitored.

For example you want to move a device and to monitor something until the motion is done.

robx.acceleration = 0.5  # let's slow down for the example

with text_block() as tb:
    step = "INIT"

    def render():
        nonlocal step
        return 1, f" {step} {robx.name}: {robx.position:0.2f} {robx.unit}"

    tb.set_render(render)
    try:
        # Init
        move(robx, 0, display_mode="no")
        # Do some stuffs
        step = "MOVE"
        move(robx, 5, display_mode="no")
        # Stabilisation
        step = "STAB"
        sleep(5.0)
    except BaseException:
        step = "ABORTED"
        raise
    step = "DONE"

Screenshot

If the user abort the task with CTRL-C, first the background task will be cancelled, then the application will refresh the display, and finally the KeyboardInterrupt will be raised. The displayed information will be consistent.

Object info

The __info__ function can also be formatted with colors and styles.

There is 3 different ways to achieve that. Here is few examples:

from bliss.shell.formatters.ansi import RED
from prompt_toolkit.formatted_text import FormattedText, ANSI, HTML

class A:
    def __info__(self):
        # The most efficient way is to provide pre-parsed content
        return FormattedText([('', 'coucou'), ('class:danger', '!!!')])

class B:
    def __info__(self):
        # The HTML markup can be useful
        return HTML("coucou<danger>!!!</danger>")

class C:
    def __info__(self):
        # ANSI is not recommended, but still can be convinient for transition.
        # This only requires to wrap your old code with `ANSI`.
        return ANSI("coucou" + RED("!!!"))

Screenshot

Style customization

By default the title <h1> is white in a dark theme.

One could prefer to have a colorful title.

Here is an example to change colors in the session setup.

from bliss.shell.pt import default_style

default_style.DARK_STYLE["h1"] = "red underline bold"

Now, every script using <h1>, or getval.title() will use this custom style.

Example for kb focusing sequence: Screenshot

See also: prompt_toolkit documentation for more information.

Another example for getval functions:

from bliss.shell.pt import default_style

# User input (default text).
default_style.SHARED_STYLE["getval"] = "white"

# Other classes
default_style.SHARED_STYLE["getval question"] = "orange bold"
default_style.SHARED_STYLE["getval prompt_char"] = "yellow"
default_style.SHARED_STYLE["getval valid_input"] = "red bold"
default_style.SHARED_STYLE["getval separator"] = ""
default_style.SHARED_STYLE["getval description"] = "blue"

Styled getval helpers

Mostly the style classes follows this template:

[valid_input][separator][description]
[valid_input][separator][description]
[valid_input][separator][description]
[question][valid_input][prompt_char][]