4.4. 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 twisted’s deferred - a framework that makes it easy to deal with callbacks. Many commands in alot make use of inline callbacks, which allow you to treat deferred-returning functions almost like syncronous functions. Consider the following example of a function that prompts for some input and acts on it:

from twisted.internet import defer

@defer.inlineCallbacks
def greet(ui):  # ui is instance of alot.ui.UI
    name = yield ui.prompt('pls enter your name')
    ui.notify('your name is: ' + name)

4.4.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 twisted) and is responsible for opening, closing and focussing buffers.

Parameters:
  • dbmanDBManager
  • initialcmdline (str) – commandline applied after setting up interface
  • colourmode (int in [1,16,256]) – determines which theme to chose
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
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={'y': 'yes', 'n': 'no'}, select=None, cancel=None, msg_position='above')

prompt user to make a choice.

Parameters:
  • message (unicode) – string to display before list of choices
  • choices (dict: keymap->choice (both str)) – dict of possible choices
  • 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:

twisted.defer.Deferred

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
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

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

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

prompt for text input. This returns a Deferred that calls back with the input string.

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:

twisted.defer.Deferred

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 = None

list of active buffers

commandprompthistory = None

history of the command line prompt

current_buffer = None

points to currently active Buffer

db_was_locked = None

flag used to prevent multiple ‘index locked’ notifications

dbman = None

Database Manager (DBManager)

input_queue = None

stores partial keyboard input

last_commandline = None

saves the last executed commandline

mode = None

interface mode identifier - type of current buffer

4.4.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
envelope EnvelopeBuffer
class alot.buffers.BufferlistBuffer(ui, filtfun=None)

lists all active buffers

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.

class alot.buffers.EnvelopeBuffer(ui, envelope)

message composition mode

toggle_all_headers()

toggles visibility of all envelope headers

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

shows a result list of threads for a query

get_selected_thread()

returns currently selected Thread

get_selected_threadline()

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

kill_filler_process()

terminates the process that fills this buffers PipeWalker.

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

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

get_selected_message()

returns focussed Message

get_selected_message_position()

returns position of focussed message in the thread tree

get_selected_messagetree()

returns currently focussed MessageTree

get_selected_mid()

returns Message ID of focussed message

get_selected_thread()

returns 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.

refresh()

refresh and flushe caches of Thread tree

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
class alot.buffers.TagListBuffer(ui, alltags=, []filtfun=None)

lists all tagstrings present in the notmuch database

get_selected_tag()

returns selected tagstring

4.4.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.4.3.1. utils

Utility Widgets not specific to alot

class alot.widgets.utils.AttrFlipWidget(w, maps, init_map='normal')

An AttrMap that can remember attributes to set

4.4.3.2. globals

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

class alot.widgets.globals.AttachmentWidget(attachment, selectable=True)

one-line summary of an Attachment.

class alot.widgets.globals.CompleteEdit(completer, on_exit, on_error=None, edit_text=u'', history=None, **kwargs)

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:calls ‘on_exit’ with value None, which can be interpreted as cancelation
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 a/e:moves curser to the beginning/end 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 completion errors
  • edit_text (str) – initial text
  • history (list or str) – initial command history
class alot.widgets.globals.HeadersList(headerslist, key_attr, value_attr, gaps_attr=None)

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(tag, fallback_normal=None, fallback_focus=None)

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.

4.4.3.3. bufferlist

Widgets specific to Bufferlist mode

class alot.widgets.bufferlist.BufferlineWidget(buffer)

selectable text widget that represents a Buffer in the BufferlistBuffer.

4.4.3.4. search

Widgets specific to search mode

class alot.widgets.search.ThreadlineWidget(tid, dbman)

selectable line widget that represents a Thread in the SearchBuffer.

4.4.3.5. thread

Widgets specific to thread mode

class alot.widgets.thread.DictList(content, key_attr, value_attr, gaps_attr=None)

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.FocusableText(txt, att, att_focus)

Selectable Text used for nodes in our example

class alot.widgets.thread.MessageSummaryWidget(message, even=True)

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(message, odd=True)

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) – Messag 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

replace_bodytext(txt)

display txt instead of current msg ‘body’

class alot.widgets.thread.ThreadTree(thread)

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.4.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.

class alot.completion.AbooksCompleter(abooks, addressesonly=False)

completes a contact from given address books

Parameters:
  • abooks (list of AddresBook) – used to look up email addresses
  • addressesonly (bool) – only insert address, not the realname of the contact
class alot.completion.AccountCompleter(**kwargs)

completes users’ own mailaddresses

class alot.completion.ArgparseOptionCompleter(parser)

completes option parameters for a given argparse.Parser

Parameters:parser (argparse.ArgumentParser) – the option parser we look up parameter and choices from
class alot.completion.CommandCompleter(dbman, mode, currentbuffer=None)

completes one command consisting of command name and parameters

Parameters:
  • dbman (DBManager) – used to look up avaliable tagstrings
  • mode (str) – mode identifier
  • currentbuffer (Buffer) – currently active buffer. If defined, this will be used to dynamically extract possible completion strings
class alot.completion.CommandLineCompleter(dbman, mode, currentbuffer=None)

completes command lines: semicolon separated command strings

Parameters:
  • dbman (DBManager) – used to look up avaliable tagstrings
  • mode (str) – mode identifier
  • currentbuffer (Buffer) – currently active buffer. If defined, this will be used to dynamically extract possible completion strings
get_context(line, pos)

computes start and end position of substring of line that is the command string under given position

class alot.completion.CommandNameCompleter(mode)

completes command names

Parameters:mode (str) – mode identifier
class alot.completion.Completer

base class for completers

complete(original, pos)

returns a list of completions and cursor positions for the string original from position pos on.

Parameters:
  • original (str) – the string to complete
  • pos (int) – starting position to complete from
Returns:

pairs of completed string and cursor position in the new string

Return type:

list of (str, int)

Raises:

CompletionError

relevant_part(original, pos, sep=' ')

calculates the subword in a sep-splitted list of substrings of original that pos is ia.n

class alot.completion.ContactsCompleter(abooks, addressesonly=False)

completes contacts from given address books

Parameters:
  • abooks (list of AddresBook) – used to look up email addresses
  • addressesonly (bool) – only insert address, not the realname of the contact
class alot.completion.CryptoKeyCompleter(private=False)

completion for gpg keys

Parameters:private (bool) – return private keys
class alot.completion.MultipleSelectionCompleter(completer, separator=', ')

Meta-Completer that turns any Completer into one that deals with a list of completion strings using the wrapped Completer. This allows for example to easily construct a completer for comma separated recipient-lists using a ContactsCompleter.

Parameters:
  • completer (Completer) – completer to use for individual substrings
  • separator (str) – separator used to split the completion string into substrings to be fed to completer.
relevant_part(original, pos)

calculates the subword of original that pos is in

class alot.completion.PathCompleter

completion for paths

class alot.completion.QueryCompleter(dbman)

completion for a notmuch query string

Parameters:dbman (DBManager) – used to look up avaliable tagstrings
class alot.completion.StringlistCompleter(resultlist, ignorecase=True, match_anywhere=False)

completer for a fixed list of strings

Parameters:
  • resultlist (list of str) – strings used for completion
  • liberal (bool) – match case insensitive and not prefix-only
class alot.completion.TagCompleter(dbman)

complete a tagstring

Parameters:dbman (DBManager) – used to look up avaliable tagstrings
class alot.completion.TagsCompleter(dbman)

completion for a comma separated list of tagstrings

Parameters:dbman (DBManager) – used to look up avaliable tagstrings