# 4.3. User Interface

Alot sets up a widget tree and a `mainloop` in the constructor of `alot.ui.UI`. The visible area is a `urwid.Frame`, where the footer is used as a status line and the body part displays the currently active `alot.buffers.Buffer`.

To be able to bind keystrokes and translate them to `Commands`, keypresses are not propagated down the widget tree as is customary in urwid. Instead, the root widget given to urwids mainloop is a custom wrapper (`alot.ui.Inputwrap`) that interprets key presses. A dedicated `SendKeypressCommand` can be used to trigger key presses to the wrapped root widget and thereby accessing standard urwid behaviour.

In order to keep the interface non-blocking and react to events like terminal size changes, alot makes use of asyncio - which allows asynchronous calls without the use of callbacks. Alot makes use of the python 3.5 async/await syntax

    async def greet(ui):  # ui is instance of alot.ui.UI
        name = await ui.prompt('pls enter your name')
        ui.notify('your name is: ' + name)

## 4.3.1. `UI` - the main component

class alot.ui.UI(dbman, initialcmdline)

  This class integrates all components of alot and offers methods for user interaction like `prompt()`, `notify()` etc. It handles the urwid widget tree and mainloop (we use asyncio) and is responsible for opening, closing and focussing buffers.

  Parameters:

    - dbman – `DBManager`

    - initialcmdline (str) – commandline applied after setting up interface

    - colourmode (int in [1,16,256]) – determines which theme to chose

  async apply_command(cmd)

    applies a command

    This calls the pre and post hooks attached to the command, as well as `cmd.apply()`.

    Parameters:

      cmd (`Command`) – an applicable command

  async apply_commandline(cmdline)

    interprets a command line string

    i.e., splits it into separate command strings, instanciates `Commands` accordingly and applies then in sequence.

    Parameters:

      cmdline (str) – command line to interpret

  buffer_close(buf, redraw=True)

    closes given `Buffer`.

    This it removes it from the bufferlist and calls its cleanup() method.

  buffer_focus(buf, redraw=True)

    focus given `Buffer`.

  buffer_open(buf)

    register and focus new `Buffer`.

  build_statusbar()

    construct and return statusbar widget

  choice(message, choices=None, select=None, cancel=None, msg_position='above', choices_to_return=None)

    prompt user to make a choice.

    Parameters:

      - message (unicode) – string to display before list of choices

      - choices (dict: keymap->choice key is str and value is any obj)) – dict of possible choices

      - choices_to_return – dict of possible choices to return for the choices of the choices of paramter

      - select (str) – choice to return if enter/return is hit. Ignored if set to None.

      - cancel (str) – choice to return if escape is hit. Ignored if set to None.

      - msg_position (str) – determines if message is above or left of the prompt. Must be above or left.

    Return type:

      asyncio.Future

  cleanup()

    Do the final clean up before shutting down.

  clear_notify(messages)

    Clears notification popups. Call this to ged rid of messages that don’t time out.

    Parameters:

      messages – The popups to remove. This should be exactly what `notify()` returned when creating the popup

  static exit()

    shuts down user interface without cleaning up. Use a `alot.commands.globals.ExitCommand` for a clean shutdown.

  get_buffers_of_type(t)

    returns currently open buffers for a given subclass of `Buffer`.

    Parameters:

      t (alot.buffers.Buffer) – Buffer class

    Return type:

      list

  get_deep_focus(startfrom=None)

    return the bottom most focussed widget of the widget tree

  async handle_signal(signum)

    handles UNIX signals

    This function currently just handles SIGUSR1. It could be extended to handle more

    Parameters:

      signum – The signal number (see man 7 signal)

  notify(message, priority='normal', timeout=0, block=False)

    opens notification popup.

    Parameters:

      - message (str) – message to print

      - priority (str) – priority string, used to format the popup: currently, ‘normal’ and ‘error’ are defined. If you use ‘X’ here, the attribute ‘global_notify_X’ is used to format the popup.

      - timeout (int) – seconds until message disappears. Defaults to the value of ‘notify_timeout’ in the general config section. A negative value means never time out.

      - block (bool) – this notification blocks until a keypress is made

    Returns:

      an urwid widget (this notification) that can be handed to `clear_notify()` for removal

  paused()

    context manager that pauses the UI to allow running external commands.

    If an exception occurs, the UI will be started before the exception is re-raised.

  prompt(prefix, text='', completer=None, tab=0, history=None)

    prompt for text input. This returns a `asyncio.Future`, which will have a string value

    Parameters:

      - prefix (str) – text to print before the input field

      - text (str) – initial content of the input field

      - completer (`alot.completion.Completer()`) – completion object to use

      - tab (int) – number of tabs to press initially (to select completion results)

      - history (list of str) – history to be used for up/down keys

    Return type:

      asyncio.Future

  show_as_root_until_keypress(w, key, afterwards=None)

    Replaces root widget by given `urwid.Widget` and makes the UI ignore all further commands apart from cursor movement. If later on key is pressed, the old root widget is reset, callable afterwards is called and normal behaviour is resumed.

  update(redraw=True)

    redraw interface

  buffers

    list of active buffers

  commandprompthistory

    history of the command line prompt

  current_buffer

    points to currently active `Buffer`

  db_was_locked

    flag used to prevent multiple ‘index locked’ notifications

  dbman

    Database Manager (`DBManager`)

  input_queue

    stores partial keyboard input

  last_commandline

    saves the last executed commandline

  mode

    interface mode identifier - type of current buffer

  recipienthistory

    history of the recipients prompt

  senderhistory

    history of the sender prompt

## 4.3.2. Buffers

A buffer defines a view to your data. It knows how to render itself, to interpret keypresses and is visible in the “body” part of the widget frame. Different modes are defined by subclasses of the following base class.

class alot.buffers.Buffer(ui, widget)

  Abstract base class for buffers.

  cleanup()

    called before buffer is closed

  get_info()

    return dict of meta infos about this buffer. This can be requested to be displayed in the statusbar.

  rebuild()

    tells the buffer to (re)construct its visible content.

Available modes are:

Mode | Buffer Subclass
--- | ---
search | `SearchBuffer`
thread | `ThreadBuffer`
bufferlist | `BufferlistBuffer`
taglist | `TagListBuffer`
namedqueries | `NamedQueriesBuffer`
envelope | `EnvelopeBuffer`

class alot.buffers.BufferlistBuffer(ui, filtfun=<function BufferlistBuffer.<lambda>>)

  lists all active buffers

  focus_first()

    Focus the first line in the buffer list.

  get_selected_buffer()

    returns currently selected `Buffer` element from list

  index_of(b)

    returns the index of `Buffer` b in the global list of active buffers.

  rebuild()

    tells the buffer to (re)construct its visible content.

class alot.buffers.EnvelopeBuffer(ui, envelope)

  message composition mode

  cleanup()

    called before buffer is closed

  get_info()

    return dict of meta infos about this buffer. This can be requested to be displayed in the statusbar.

  rebuild()

    tells the buffer to (re)construct its visible content.

  set_displaypart(part)

    Update the view to display body part (plaintext, html, src).

    ..note:: This assumes that selv.envelope.body_html exists in case the requested part is ‘html’ or ‘src’!

  toggle_all_headers()

    Toggle visibility of all envelope headers.

class alot.buffers.NamedQueriesBuffer(ui, filtfun)

  lists named queries present in the notmuch database

  focus_first()

    Focus the first line in the query list.

  get_info()

    return dict of meta infos about this buffer. This can be requested to be displayed in the statusbar.

  get_selected_query()

    returns selected query

  rebuild()

    tells the buffer to (re)construct its visible content.

class alot.buffers.SearchBuffer(ui, initialquery='', sort_order=None)

  shows a result list of threads for a query

  get_info()

    return dict of meta infos about this buffer. This can be requested to be displayed in the statusbar.

  get_selected_thread()

    returns currently selected `Thread`

  get_selected_threadline()

    returns curently focussed `alot.widgets.ThreadlineWidget` from the result list.

  rebuild(reverse=False, restore_focus=True)

    tells the buffer to (re)construct its visible content.

class alot.buffers.TagListBuffer(ui, alltags=None, filtfun=<function TagListBuffer.<lambda>>)

  lists all tagstrings present in the notmuch database

  focus_first()

    Focus the first line in the tag list.

  get_selected_tag()

    returns selected tagstring

  rebuild()

    tells the buffer to (re)construct its visible content.

class alot.buffers.ThreadBuffer(ui, thread)

  displays a thread as a tree of messages.

  Parameters:

    - ui (`UI`) – main UI

    - thread (`Thread`) – thread to display

  collapse(msgpos)

    collapse message at given position

  collapse_all()

    collapse all messages in thread

  expand(msgpos)

    expand message at given position

  expand_all()

    expand all messages in thread

  focus_first()

    set focus to first message of thread

  focus_first_reply()

    move focus to first reply to currently focussed message

  focus_last_reply()

    move focus to last reply to currently focussed message

  focus_next()

    focus next message in depth first order

  focus_next_matching(querystring)

    focus next matching message in depth first order

  focus_next_sibling()

    focus next sibling of currently focussed message in thread tree

  focus_next_unfolded()

    focus next unfolded message in depth first order

  focus_parent()

    move focus to parent of currently focussed message

  focus_prev()

    focus previous message in depth first order

  focus_prev_matching(querystring)

    focus previous matching message in depth first order

  focus_prev_sibling()

    focus previous sibling of currently focussed message in thread tree

  focus_prev_unfolded()

    focus previous unfolded message in depth first order

  focus_property(prop, direction)

    does a walk in the given direction and focuses the first message tree that matches the given property

  focus_selected_message()

    focus the summary line of currently focussed message

  get_focus()

    Get the focus from the underlying body widget.

  get_info()

    return dict of meta infos about this buffer. This can be requested to be displayed in the statusbar.

  get_messagetree_positions()

    Return a Generator to walk through all positions of `MessageTree` in the `ThreadTree` of this buffer.

  get_selected_message()

    Return focussed `Message`.

  get_selected_message_position()

    Return position of focussed message in the thread tree.

  get_selected_messagetree()

    Return currently focussed `MessageTree`.

  get_selected_mid()

    Return Message ID of focussed message.

  get_selected_thread()

    Return the displayed `Thread`.

  messagetree_at_position(pos)

    get `MessageTree` for given position

  messagetrees()

    returns a Generator of all `MessageTree` in the `ThreadTree` of this buffer.

  rebuild()

    tells the buffer to (re)construct its visible content.

  refresh()

    Refresh and flush caches of Thread tree.

  set_focus(pos)

    Set the focus in the underlying body widget.

  unfold_matching(querystring, focus_first=True)

    expand all messages that match a given querystring.

    Parameters:

      - querystring (str) – query to match

      - focus_first (bool) – set the focus to the first matching message

## 4.3.3. Widgets

What follows is a list of the non-standard urwid widgets used in alot. Some of them respect user settings, themes in particular.

### 4.3.3.1. utils

Utility Widgets not specific to alot

class alot.widgets.utils.AttrFlipWidget(*args: Any, **kwargs: Any)

  An AttrMap that can remember attributes to set

class alot.widgets.utils.DialogBox(*args: Any, **kwargs: Any)

### 4.3.3.2. globals

This contains alot-specific `urwid.Widget` used in more than one mode.

class alot.widgets.globals.AttachmentWidget(*args: Any, **kwargs: Any)

  one-line summary of an `Attachment`.

class alot.widgets.globals.ChoiceWidget(*args: Any, **kwargs: Any)

class alot.widgets.globals.CompleteEdit(*args: Any, **kwargs: Any)

  This is a vamped-up `urwid.Edit` widget that allows for tab-completion using `Completer` objects

  These widgets are meant to be used as user input prompts and hence react to ‘return’ key presses by calling a ‘on_exit’ callback that processes the current text value.

  The interpretation of some keypresses is hard-wired:
    enter:

      calls ‘on_exit’ callback with current value

    esc/ctrl g:

      calls ‘on_exit’ with value None, which can be interpreted as cancellation

    tab:

      calls the completer and tabs forward in the result list

    shift tab:

      tabs backward in the result list

    up/down:

      move in the local input history

    ctrl f/b:

      moves curser one character to the right/left

    meta f/b shift right/left:

      moves the cursor one word to the right/left

    ctrl a/e:

      moves curser to the beginning/end of the input

    ctrl d:

      deletes the character under the cursor

    meta d:

      deletes everything from the cursor to the end of the next word

    meta delete/backspace ctrl w:

      deletes everything from the cursor to the beginning of the current word

    ctrl k:

      deletes everything from the cursor to the end of the input

    ctrl u:

      deletes everything from the cursor to the beginning of the input

  Parameters:

    - completer (alot.completion.Completer) – completer to use

    - on_exit (callable) – “enter”-callback that interprets the input (str)

    - on_error (callback) – callback that handles `alot.errors.CompletionErrors`

    - edit_text (str) – initial text

    - history (list or str) – initial command history

class alot.widgets.globals.HeadersList(*args: Any, **kwargs: Any)

  renders a pile of header values as key/value list

  Parameters:

    - headerslist (list of (str, str)) – list of key/value pairs to display

    - key_attr (urwid.AttrSpec) – theming attribute to use for keys

    - value_attr (urwid.AttrSpec) – theming attribute to use for values

    - gaps_attr (urwid.AttrSpec) – theming attribute to wrap lines in

class alot.widgets.globals.TagWidget(*args: Any, **kwargs: Any)

  text widget that renders a tagstring.

  It looks up the string it displays in the tags section of the config as well as custom theme settings for its tag.

  Attributes that should be considered publicly readable:
    attr tag:

      the notmuch tag

    type tag:

      str

### 4.3.3.3. bufferlist

Widgets specific to Bufferlist mode

class alot.widgets.bufferlist.BufferlineWidget(*args: Any, **kwargs: Any)

  selectable text widget that represents a `Buffer` in the `BufferlistBuffer`.

### 4.3.3.4. search

Widgets specific to search mode

class alot.widgets.search.ThreadlineWidget(*args: Any, **kwargs: Any)

  selectable line widget that represents a `Thread` in the `SearchBuffer`.

alot.widgets.search.build_tags_part(tags, attr_normal, attr_focus)

  create an urwid.Columns widget (wrapped in approproate Attributes) to display a list of tag strings, as part of a threadline.

  Parameters:

    - tags (list of str) – list of tag strings to include

    - attr_normal – urwid attribute to use if unfocussed

    - attr_focus – urwid attribute to use if focussed

  Returns:

    overall width in characters and a Columns widget.

  Return type:

    tuple[int, urwid.Columns]

alot.widgets.search.build_text_part(name, thread, struct)

  create an urwid.Text widget (wrapped in approproate Attributes) to display a plain text parts in a threadline. create an urwid.Columns widget (wrapped in approproate Attributes) to display a list of tag strings, as part of a threadline.

  Parameters:

    - name (str) – id of part to build

    - thread (`alot.db.thread.Thread`) – the thread to get local info for

    - struct (dict) – theming attributes for this part, as provided by `alot.settings.theme.Theme.get_threadline_theming`

  Returns:

    overall width (in characters) and a widget.

  Return type:

    tuple[int, AttrFliwWidget]

alot.widgets.search.prepare_string(partname, thread, maxw)

  extract a content string for part ‘partname’ from ‘thread’ of maximal length ‘maxw’.

### 4.3.3.5. thread

Widgets specific to thread mode

class alot.widgets.thread.DictList(*args: Any, **kwargs: Any)

  `SimpleTree` that displays key-value pairs.

  The structure will obey the Tree API but will not actually be a tree but a flat list: It contains one top-level node (displaying the k/v pair in Columns) per pair. That is, the root will be the first pair, its sibblings will be the other pairs and first|last_child will always be None.

  Parameters:

    - headerslist (list of (str, str)) – list of key/value pairs to display

    - key_attr (urwid.AttrSpec) – theming attribute to use for keys

    - value_attr (urwid.AttrSpec) – theming attribute to use for values

    - gaps_attr (urwid.AttrSpec) – theming attribute to wrap lines in

class alot.widgets.thread.MessageSummaryWidget(*args: Any, **kwargs: Any)

  one line summary of a `Message`.

  Parameters:

    - message (alot.db.Message) – a message

    - even (bool) – even entry in a pile of messages? Used for theming.

class alot.widgets.thread.MessageTree(*args: Any, **kwargs: Any)

  `Tree` that displays contents of a single `alot.db.Message`.

  Its root node is a `MessageSummaryWidget`, and its child nodes reflect the messages content (parts for headers/attachments etc).

  Collapsing this message corresponds to showing the summary only.

  Parameters:

    - message (alot.db.Message) – Message to display

    - odd (bool) – theme summary widget as if this is an odd line (in the message-pile)

  collapse_if_matches(querystring)

    collapse (and show summary only) if the `alot.db.Message` matches given querystring

  expand(pos)

    overload CollapsibleTree.expand method to ensure all parts are present. Initially, only the summary widget is created to avoid reading the messafe file and thus speed up the creation of this object. Once we expand = unfold the message, we need to make sure that body/attachments exist.

  set_mimepart(mimepart)

    Set message widget mime part and invalidate body tree.

class alot.widgets.thread.TextlinesList(*args: Any, **kwargs: Any)

  `SimpleTree` that contains a list of all-level-0 Text widgets for each line in content.

class alot.widgets.thread.ThreadTree(*args: Any, **kwargs: Any)

  `Tree` that parses a given `alot.db.Thread` into a tree of `MessageTrees` that display this threads individual messages. As MessageTreess are not urwid widgets themself this is to be used in combination with `NestedTree` only.

## 4.3.4. Completion

`alot.ui.UI.prompt()` allows tab completion using a `Completer` object handed as ‘completer’ parameter. `alot.completion` defines several subclasses for different occasions like completing email addresses from an `AddressBook`, notmuch tagstrings. Some of these actually build on top of each other; the `QueryCompleter` for example uses a `TagsCompleter` internally to allow tagstring completion after “is:” or “tag:” keywords when typing a notmuch querystring.

All these classes overide the method `complete()`, which for a given string and cursor position in that string returns a list of tuples (completed_string, new_cursor_position) that are taken to be the completed values. Note that completed_string does not need to have the original string as prefix. `complete()` may rise `alot.errors.CompletionError` exceptions.