User Guide#

pw_console: Multi-purpose pluggable interactive console for dev & manufacturing

Tip

This guide can be viewed while running pw_console under the [Help] menu or online at: https://pigweed.dev/pw_console/py/pw_console/docs/user_guide.html

The Pigweed Console provides a Python repl (read eval print loop) and log viewer in a single-window terminal based interface.

Starting the Console#

Launching the console may be different if you implement your own custom console startup script. To launch pw_console in upstream Pigweed you can run in test mode with pw-console --test-mode.

See also

Running pw_console for the stm32f429i-disc1: STM32Cube and Host Device Simulator targets.

Exiting#

There are a few ways to exit the Pigweed Console user interface:

  1. Click the [File] menu and then Exit.

  2. Type quit or exit in the Python Input window and press Enter.

  3. Press Ctrl-d once to show the quit confirmation dialog. From there press Ctrl-d a second time or y will exit.

  4. Press Ctrl-x quickly followed by Ctrl-c will exit without confirmation.

  5. Press Ctrl-p to search for commands, type exit, then press Enter.

Interface Layout#

On startup the console will display multiple windows one on top of the other.

+---------------------------------------------------------+
| [File] [Edit] [View] [Window] [Help]    Pigweed Console |
+=========================================================+
|                                                         |
|                                                         |
|                                                         |
| Log Window                                              |
+=========================================================+
|                                                         |
|                                                         |
| Python Results                                          |
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - -+
|                                                         |
| Python Input                                            |
+---------------------------------------------------------+

Color Depth#

Some terminals support full 24-bit color and pw console will use that by default in most cases. One notable exeception is Apple Terminal on MacOS which supports 256 colors only. iTerm2 is a good MacOS alternative that supports 24-bit colors.

To force a particular color depth: set one of these environment variables before launching the console. For bash and zsh shells you can use the export command.

# 1 bit | Black and white
export PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_1_BIT
# 4 bit | ANSI colors
export PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_4_BIT
# 8 bit | 256 colors
export PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_8_BIT
# 24 bit | True colors
export PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_24_BIT

For Windows command prompt (cmd.exe) use the set command:

set PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_1_BIT
set PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_4_BIT
set PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_8_BIT
set PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_24_BIT

Configuration#

Pigweed Console supports loading project and user specific settings stored in YAML files. Each file follows the same format and are loaded one after the other. Any setting specified multiple locations will be overridden by files loaded later in the startup sequence.

  1. $PW_PROJECT_ROOT/.pw_console.yaml

    Project level config file. This is intended to be a file living somewhere under a project folder and is checked into version control. It serves as a base config for all users to inherit from.

  2. $PW_PROJECT_ROOT/.pw_console.user.yaml

    User’s personal config file for a specific project. This can be a file that lives in a project folder but is git-ignored and not checked into version control. This lets users change settings applicable to this project only.

  3. $HOME/.pw_console.yaml

    A global user based config file. This file is located in the user’s home directory and settings here apply to all projects. This is a good location to set appearance options such as:

    ---
    config_title: pw_console
    ui_theme: nord
    code_theme: pigweed-code
    swap_light_and_dark: False
    spaces_between_columns: 2
    hide_date_from_log_time: False
    

It’s also possible to specify a config file via a shell environment variable. If this method is used only this config file is applied. Project and user config file options will not be set.

export PW_CONSOLE_CONFIG_FILE=/home/.config/pw_console/config.yaml

Example Config#

---
config_title: pw_console

# Repl and Search History files
# Setting these to a file located $PW_PROJECT_ROOT is a
# good way to make Python repl history project specific.

# Default: $HOME/.pw_console_history
repl_history: $PW_PROJECT_ROOT/.pw_console_history

# Default: $HOME/.pw_console_search
search_history: $PW_PROJECT_ROOT/.pw_console_search

# Theme Settings

# Default: dark
ui_theme: high-contrast-dark

# Default: pigweed-code
code_theme: material

# Default: False
swap_light_and_dark: False

# Log Table View Settings

# Number of spaces to insert between columns
# Default: 2
spaces_between_columns: 2

# Hide the year month and day from the time column.
hide_date_from_log_time: False

# Style the log message to match the level. For example:
# Warning text is all yellow, ERROR and Critical are red.
recolor_log_lines_to_match_level: True

# Do not re-style log messages. This will preserve any ansi escape sequences
# for color.
recolor_log_lines_to_match_level: False

# Show the Python file and line number responsible for creating log messages.
show_python_file: False
# Show the Python logger responsible for creating log messages.
show_python_logger: False
# Show the 'file' metadata column.
show_source_file: False

# Custom Column Ordering
# By default columns are ordered as:
#   time, level, metadata1, metadata2, ..., message
# The log message is always the last value and not required in this list.
column_order:
  # Column name
  - time
  - level
  - metadata1
  - metadata2

# If True, any metadata field not listed above in 'column_order'
# will be hidden in table view.
column_order_omit_unspecified_columns: False

# Unique Colors for Column Values
#   Color format: 'bg:#BG-HEX #FG-HEX STYLE'
# All parts are optional.
# Empty strings will leave styling unchanged.
column_colors:
  # Column name
  time:
  level:
  metadata1:
    # Field values
    # Default will be applied if no match found
    default: '#98be65'
    BATTERY: 'bg:#6699cc #000000 bold'
    CORE1: 'bg:#da8548 #000000 bold'
    CORE2: 'bg:#66cccc #000000 bold'
  metadata2:
    default: '#ffcc66'
    APP: 'bg:#ff6c6b #000000 bold'
    WIFI: '#555555'

# Each window column is normally aligned side by side in vertical splits. You
# can change this to one group of windows on top of the other with horizontal
# splits using this method

# Default: vertical
window_column_split_method: vertical

# Window Layout
windows:
  # First window column (vertical split)
  # Each split should have a unique name and include either
  # 'stacked' or 'tabbed' to select a window pane display method.
  Split 1 stacked:
    # Items here are window titles, each should be unique.
    # Window 1
    Device Logs:
      height: 33  # Weighted value for window height
      hidden: False  # Hide this window if True
    # Window 2
    Python Repl:
      height: 67
    # Window 3
    Host Logs:
      hidden: True

  # Second window column
  Split 2 tabbed:
    # This is a duplicate of the existing 'Device Logs' window.
    # The title is 'NEW DEVICE'
    NEW DEVICE:
      duplicate_of: Device Logs
      # Log filters are defined here
      filters:
        # Metadata column names here or 'all'
        source_name:
          # Matching method name here
          # regex, regex-inverted, string, string-inverted
          regex: 'USB'
        module:
          # An inverted match will remove matching log lines
          regex-inverted: 'keyboard'
    NEW HOST:
      duplicate_of: Host Logs
      filters:
        all:
          string: 'FLASH'

  # Third window column
  Split 3 tabbed:
    # This is a brand new log Window
    Keyboard Logs - IBM:
      loggers:
        # Python logger names to include in this log window
        my_cool_keyboard_device:
          # Level the logger should be set to.
          level: DEBUG
        # The empty string logger name is the root Python logger.
        # In most cases this should capture all log messages.
        '':
          level: DEBUG
      filters:
        all:
          regex: 'IBM Model M'
    Keyboard Logs - Apple:
      loggers:
        my_cool_keyboard_device:
          level: DEBUG
      filters:
        all:
          regex: 'Apple.*USB'

# Command Runner dialog size and position
command_runner:
  width: 80
  height: 10
  position:
    top: 3  # 3 lines below the top edge of the screen
    # Alternatively one of these options can be used instead:
    # bottom: 2  # 2 lines above the bottom edge of the screen
    # left: 2    # 2 lines away from the left edge of the screen
    # right: 2   # 2 lines away from the right edge of the screen

# Key bindings can be changed as well with the following format:
#   named-command: [ list_of_keys ]
# Where list_of_keys is a string of keys one for each alternate key
# To see all named commands open '[Help] > View Key Binding Config'
# See below for the names of special keys
key_bindings:
  log-pane.move-cursor-up:
  - j
  - up
  log-pane.move-cursor-down:
  - k
  - down
  log-pane.search-next-match:
  - n
  log-pane.search-previous-match:
  - N

  # Chorded keys are supported.
  # For example, 'z t' means pressing z quickly followed by t.
  log-pane.shift-line-to-top:
  - z t
  log-pane.shift-line-to-center:
  - z z

# Project and User defined Python snippets
# Press Ctrl-t the Python Repl to select which snippet to insert.

# Python Repl Snippets (Project owned)
snippets:
  Count Ten Times:
    code: |
      for i in range(10):
          print(i)
    description: |
      Print out 1 through 10 each on a separate line

  Local Variables:
    code: |
      locals()
    description: |
      Return all local Python variables.

# Python Repl Snippets (User owned)
user_snippets:
  Pretty print format function:
    code: |
      import pprint
      _pretty_format = pprint.PrettyPrinter(indent=1, width=120).pformat
    description: |
      Create a function named `_pretty_format` which returns a pretty
      formatted string for a Python object.

      Example:

      ```python
      from dataclasses import dataclass

      @dataclass
      class CodeSnippet:
          title: str
          code: str
          description: str = ''

      _pretty_format(CodeSnippet('one', '1'))
      ```

      The last line will return the string:

      ```
      "CodeSnippet(title='one', code='1', description='')"
      ```

  Global variables:
    code: |
      globals()
    description: |
      Return all global Python variables.

Python Repl Snippets#

Python code snippets can be defined under the snippets: or user_snippets: section. We suggest reserving user_snippets: for the user based config files ($HOME/.pw_console.yaml or $PW_PROJECT_ROOT/.pw_console.user.yaml). snippets: is best suited for a project specific config file shared by all team members: $PW_PROJECT_ROOT/.pw_console.yaml

Snippets consist of a title followed by code: | and optionally description: |. The YAML operator | will concatenate the following lines into a string and strip leading whitespace.

snippets:
  Count Ten Times:
    code: |
      for i in range(10):
          print(i)
    description: |
      Print out 1 through 10 each on a separate line

Inserting this snippet will paste the for loop above into the Python Repl input window.

Descriptions are markdown formatted and displayed below the selected snippet window. Fenced code blocks will have the correct syntax highlighting applied. For example the following will apply Python syntax highlighting to the code block below Example:.

snippets:
  Pretty print format function:
    code: |
      import pprint
      _pretty_format = pprint.PrettyPrinter(indent=1, width=120).pformat
    description: |
      Create a function named `_pretty_format` which returns a pretty
      formatted string for a Python object.

      Example:

      ```python
      from dataclasses import dataclass

      @dataclass
      class CodeSnippet:
          title: str
          code: str
          description: str = ''

      _pretty_format(CodeSnippet('one', '1'))
      ```

If identical description text needs to be repeated for multiple snippets in a row you can set description: USE_PREVIOUS. For example these two snippets will have the same description text: Helper functions for pretty printing Python objects.

snippets:
  Pretty print format function:
    code: |
      import pprint
      _pretty_format = pprint.PrettyPrinter(indent=1, width=120).pformat
    description: |
      Helper functions for pretty printing Python objects.

  Pretty print function:
    code: |
      import pprint
      _pretty_print = pprint.PrettyPrinter(indent=1, width=120).pprint
    description: USE_PREVIOUS

Changing Keyboard Shortcuts#

Pigweed Console uses prompt_toolkit to manage its keybindings.

Bindings can be changed in the YAML config file under the key_bindings: section by adding a named function followed by a of keys to bind. For example this config sets the keys for log pane cursor movement.

  • Moving down is set to j or the Down arrow.

  • Moving up is set to k or the Up arrow.

key_bindings:
  log-pane.move-cursor-down:
  - j
  - down
  log-pane.move-cursor-up:
  - k
  - up

List of Special Key Names#

This table is from prompt_toolkit’s List of special keys.

Keyboard Function

Key Values

Literal characters

a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0 ! @ # $ % ^ & * ( ) - _ + = ~

Escape and Shift-Escape

escape s-escape

Arrows

left right up down

Navigation

home end delete pageup pagedown insert

Control-letter

c-a c-b c-c c-d c-e c-f c-g c-h c-i c-j c-k c-l c-m c-n c-o c-p c-q c-r c-s c-t c-u c-v c-w c-x c-y c-z

Control-number

c-1 c-2 c-3 c-4 c-5 c-6 c-7 c-8 c-9 c-0

Control-arrow

c-left c-right c-up c-down

Other control keys

c-@ c-\ c-] c-^ c-_ c-delete

Shift-arrow

s-left s-right s-up s-down

Control-Shift-arrow

c-s-left c-s-right c-s-up c-s-down

Other Shift` keys

s-delete s-tab

F Keys

f1  f2  f3  f4  f5  f6  f7  f8  f9  f10 f11 f12 f13 f14 f15 f16 f17 f18 f19 f20 f21 f22 f23 f24

There are some key aliases as well. Most of these exist due to how keys are processed in VT100 terminals. For example when pressing Tab terminal emulators receive Ctrl-i.

Key

Key Value Alias

Space

space

c-h

backspace

c-@

c-space

c-m

enter

c-i

tab

Binding Alt / Option / Meta#

In terminals the Alt key is converted into a leading Escape key press. For example pressing Alt-t actually sends the Escape key followed by the t key. Similarly Ctrl-Alt-t sends Escape followed by Ctrl-t.

To bind Alt (or Option on MacOS) add escape before the key that should be modified.

key_bindings:
  window-manager.move-pane-down:
  - escape c-up  # Alt-Ctrl-up
  window-manager.move-pane-left:
  - escape c-left  # Alt-Ctrl-left
  window-manager.move-pane-right:
  - escape c-right  # Alt-Ctrl-right
  window-manager.move-pane-up:
  - escape c-down  # Alt-Ctrl-down

Key Sequence Bindings#

Bindings can consist of multiple key presses in sequence. This is also known as chorded keys. Multiple keys separated by spaces define a chorded key binding. For example to bind z quickly followed by t use z t.

key_bindings:
  log-pane.shift-line-to-top:
  - z t
  log-pane.shift-line-to-center:
  - z z

Known Issues#

Log Window#

Upcoming Features#

Open feature requests: https://issues.pigweed.dev/issues?q=status:open%20pw_console%20type:feature_request

Feature Requests#

Set the Type field to Feature Request when creating an issue: https://issues.pigweed.dev/issues/new?component=1194524&template=1691892