summaryrefslogtreecommitdiff
path: root/README
blob: f3d3df47dd0eb212769a80b8bc86cd0a9ad5f0c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
This is a proposal for a terminal gui for notmuch mail, written in python.
The key ideas are:

* OOP approach using python 
* aim at the look and feel of sup for now
* use libraries whenever possible. 
  urwid: http://excess.org/urwid/ 
  The notmuch bindings: https://bitbucket.org/spaetz/cnotmuch/
  (mailbox: http://docs.python.org/library/mailbox.html)
  (urwid-satext: http://wiki.goffi.org/wiki/Urwid-satext)
  (configparser)

You need the notmuch python bindings and urwid to run it. I run it like this 
> python ng.py -l debug.log -d debug
and "tail -f debug.log" in another window.

At the moment you can play with the global bindings
i, open inbox
u, open unread 
s, python shell
\, prompts and stars search
v, opens log in vim
x, closes current buffer
tab, tabs between buffers
;, opens bufferlist

and buffer specific bindings:
in search: enter, select thread, (look at log, not implemented) 
in bufferlist: d, removes selected buffer, enter selects.


Here is an overview of the current architecture.

ng.ui.UI 
contains the main component: it
 - handles the urwid.MainLoop that manages the screen etc.
 - contains a logging.logger that can be used for log/debug messages like so:
   ui.logger.info('hello logworld')
 - sets up and updates the header/footer/body widgets
 - is able to open/close/focus buffers (there's a list ui.buffers of currently
   known buffers, and a ui.current_buffer, pointing to the focussed one)
 - handles global keybindings. See below for more on bindings.
 - can apply (and further down the road undo/redo) commands (see command.py)
 - is able to open a prompt/dialogs

ng.db.DBManager 
interface to the notmuch index. Currently, it has very limited functionality,
but should be able to to this:
 - store the connection settings (index path and whether or not we use a
   read_only connection..)
 - two basic methods for reading from and writing to the index. Lets call it
   dbman.query(querystring) and dbman.update(updatestring).  query will return
   a notmuch.Query object, i haven't bothered with update so far.
 - a method for all interesting operations on the index These will use
   self.query/update accordingly. See dbman.count_messages for a simple example

ng.buffer.Buffer
Is used as a base class for different types of buffers, or display-modi if you
like. So far there's only a SearchBuffer (might be a bad name) that displays
the result of a search for mail threads, and a BufferListBuffer, that displays
a list of buffers. Technically, ng.buffer.Buffer inherits from urwid.AttrMap.
This is done so that it can be directly be set as the body-part of the main
gui, thereby intercepting (and filter/handle according to local bindings) the
key presses. A Buffer
 - is a widget, that can be drawn,focussed etc as all widgets.
 - has a pointer to the main ui, a typename, (e.g. search results, display
   single thread, envelope, logmode) and knows how to summarise itself.
 - knows how to handle local (mode-specific) keybindings (self.bindings see
   below)

ng.commands.Command
Again, a base class for different commands. A command is an object that
represents an atomic action. It will only be be applied once (and is then
stored in a undo-list somewhere). It
 - has a typename, that is used to identify a type of command for the command
   factory
 - can be applied using cmd.apply with a fixed interface: I  assume we want at
   least pointers to the main ui and the dbman objects here
 - should contain a help-info about what it does (to automagically create
   dynamic help-buffers later on)
 - should know if its undoable, and if so, implement undo() and redo()
 - points to pre and post hooks. This might get tricky with undoable cmds.. The
   idea is, that a cmd gets applied (see ng.ui.UI.apply_command), also its pre
   and posthooks are called if defined. These should have the same signature as
   cmd.apply(). See settings.hooks for an example.  There's a number of
   commands i already implemented. Each one should be created by the
   ng.command.factory (which also attaches the hooks)

ng.widgets
contains the urwid.Widgets i use do draw notmuch objects. There's a Threadline
widget for example, that knows how to present a notmuch.thread object as a
textline. Should be pretty self explanatory, definitely needs some love.  These
inherit from AttrMap, which is not very clean i guess, but they must be
"selectable" so that we can use them in a urwid.ListBox (which displays a list
and can focus elements). Since ThreadlineWidget is selectable it must include a
dummy keypress method.

ng.hooks
this should later on include methods that look for and call? hooks.  The idea
is that a user might define either python callables or paths to binaries, and
ng.hooks.get_hook(hookname) retrieves them so that they can be placed in
commands.  This might be a totally stupid idea

ng.walker
Contains urwid.ListWalker derived classes that implement a listwalker (the
content-part of a urwid.ListBox widget) that dynamically allocates its content.
The thing is that if one makes a query for all threads in the index and naively
creating a ng.widgets.ThreadlineWidget for each and placing them in a
urwid.Listbox (actually a urwid.SimplieListWalker, and /that/ in a listbox),
one this will potentially eat up your memory and take a long time. So
ng.walker.IteratorWalker will dynamically create its next element from the next
element of the iterator. For now, there's a NotmuchIteratorWalker class that
does the same for notmuch's one-time iterators. This is almost certainly a bad
idea methinks.

Key Bindings
Are currently a hash in objects of the classes ng.ui.UI and ng.buffer.Buffer.
Obviously, a key is first handed to the current buffer and in case it doesn't
handle it, it will be handled by the main UI.  Each buffer-subclass comes with
its own default local bindings which whi might want to overwrite at some point.
I guess we should have a "map" command that takes a buffertype, a key and
something to call.  For now, a key in the binding hash is a string that
represents a keypress (urwid style: 'shift j', 'k' etc are valid).  The value
is then a pair of (commandtypestring, parameterhash), that is used by the
command.factory to instantiate a command with of type commandtypestring with
parameters parameterhash. Values in the parameterhash will be called at cmd
creation by command.factory if callable. See self.bindings in
ng.buffer.BufferListBuffer for an example.