[RFC][alot] design decisions
[notmuch-archives.git] / b6 / 68bc6939f83d62b9ad4c365df8a4ea676ec316
1 Return-Path: <patricktotzke@googlemail.com>\r
2 X-Original-To: notmuch@notmuchmail.org\r
3 Delivered-To: notmuch@notmuchmail.org\r
4 Received: from localhost (localhost [127.0.0.1])\r
5         by olra.theworths.org (Postfix) with ESMTP id 43591431FAF\r
6         for <notmuch@notmuchmail.org>; Wed, 21 Mar 2012 02:07:28 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -0.799\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.799 tagged_above=-999 required=5\r
12         tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,\r
13         FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
14 Received: from olra.theworths.org ([127.0.0.1])\r
15         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
16         with ESMTP id QiFZfOGmUaQm for <notmuch@notmuchmail.org>;\r
17         Wed, 21 Mar 2012 02:07:27 -0700 (PDT)\r
18 Received: from mail-wi0-f179.google.com (mail-wi0-f179.google.com\r
19         [209.85.212.179]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
20         (No client certificate requested)\r
21         by olra.theworths.org (Postfix) with ESMTPS id 3FCE7431FAE\r
22         for <notmuch@notmuchmail.org>; Wed, 21 Mar 2012 02:07:27 -0700 (PDT)\r
23 Received: by wibhn6 with SMTP id hn6so938225wib.2\r
24         for <notmuch@notmuchmail.org>; Wed, 21 Mar 2012 02:07:26 -0700 (PDT)\r
25 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\r
26         d=googlemail.com; s=20120113;\r
27         h=content-type:mime-version:content-transfer-encoding:to:message-id\r
28         :from:user-agent:subject:date;\r
29         bh=fKKVWMfpPhBa+YjVOMkXNQETWGr8KdMJXHAPWEAg2V4=;\r
30         b=zAnBO89XvQgv/sstFTsGIajSZSd79qBQCjSigiRSyHDyrvNZMQaZfyyoXwRU1STXvy\r
31         w4kk1FwF0kwh60eLGO4Yz9RcCV7rfBIXsBJiIb7BSaty+a2wsYLTgkCgMU2ETPofnNvH\r
32         4TRh4In7/6MsWcws0B/ax1TQ0PujNFyCr+Wy3NU3FbJ1ivnM5lac2JBoNP3UJCD2hBLo\r
33         rwsiJRqoXu8Co7QDoBtMqGOEGwUGssCHQxO5bvepKZ+yl/GOzNp9FD966Gwm/78DROxl\r
34         N0iXc89Y3SvhJqWjIFhoFl98FpPLFP0zeYLzULGW/VLmtIpvpIcC/MPuN/BXF2+9yAbR\r
35         XPww==\r
36 Received: by 10.180.100.2 with SMTP id eu2mr7238366wib.1.1332320845915;\r
37         Wed, 21 Mar 2012 02:07:25 -0700 (PDT)\r
38 Received: from localhost (cpc1-sgyl2-0-0-cust548.18-2.cable.virginmedia.com.\r
39         [82.41.10.37])\r
40         by mx.google.com with ESMTPS id e6sm2985347wix.8.2012.03.21.02.07.24\r
41         (version=TLSv1/SSLv3 cipher=OTHER);\r
42         Wed, 21 Mar 2012 02:07:24 -0700 (PDT)\r
43 Content-Type: text/plain; charset="utf-8"\r
44 MIME-Version: 1.0\r
45 Content-Transfer-Encoding: quoted-printable\r
46 To: Notmuch Mail <notmuch@notmuchmail.org>\r
47 Message-ID: <20120321090722.6892.24383@brick.lan>\r
48 From: Patrick Totzke <patricktotzke@googlemail.com>\r
49 User-Agent: alot/0.3\r
50 Subject: [RFC][alot] design decisions\r
51 Date: Wed, 21 Mar 2012 09:07:22 +0000\r
52 X-BeenThere: notmuch@notmuchmail.org\r
53 X-Mailman-Version: 2.1.13\r
54 Precedence: list\r
55 List-Id: "Use and development of the notmuch mail system."\r
56         <notmuch.notmuchmail.org>\r
57 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
58         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
59 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
60 List-Post: <mailto:notmuch@notmuchmail.org>\r
61 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
62 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
63         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
64 X-List-Received-Date: Wed, 21 Mar 2012 09:07:28 -0000\r
65 \r
66 Hi all,\r
67 \r
68 with alot 0.3 released, I started thinking seriously about proper=E2=84=A2 =\r
69 MIME-display and gnupg\r
70 integration for alot. I have to make a few design decisions here and could =\r
71 really use\r
72 some informed opinions from more experienced UI developers. My question in =\r
73 particular is: =\r
74 \r
75 \r
76  How do I best integrate calls to external mime-handlers into my MVC event =\r
77 driven code?\r
78 \r
79 I mostly know how to implement the individual parts but I struggle coming u=\r
80 p with a\r
81 consistent way of organizing it all without compromising my current layout.\r
82 \r
83 \r
84 Background\r
85 ----------\r
86 \r
87 Model. Alot uses an abstraction layer over notmuch's thread, message and da=\r
88 tabase objects\r
89 to make them less fragile and generally behave more OOP-y: You can e.g. dir=\r
90 ectly call\r
91 message.add_tags(['foo','bar']) and so on. This is made possible by a "Data=\r
92 baseManager"\r
93 that maintains centralized and queued access to the notmuch index and deals=\r
94  with notmuch\r
95 exceptions like a locked index [0].\r
96 \r
97 View/Controler. We use an event-driven interface (urwid.TwistedEventLoop, [=\r
98 1]) that\r
99 handles user input and maintains a tree of widgets that knows how to render=\r
100  itself.\r
101 Twisted offers a neat concept of "Deferreds" to organize call- and errbacks=\r
102  that we\r
103 already make use of [2].  Alot has a "MessageWidget" that displays a single=\r
104  message.\r
105 \r
106 We can easily access and parse email messages into MIME-trees (msg.get_emai=\r
107 l() returns a\r
108 email.message object; pythons email module allows extensive and RFC complia=\r
109 nt dealing with\r
110 this [3]).\r
111 \r
112 We already offer full compatibility with the mailcap protocol to constuct s=\r
113 hell commands\r
114 of external MIME handlers.\r
115 \r
116 We know how to call external commands asynchronously; `alot.helper.call_cmd=\r
117 _async` does this\r
118 and returns a Deferred to which we can connect callback functions.\r
119 \r
120 \r
121 Objective\r
122 ---------\r
123 We want to turn a email.message into nicely rendered text and display it as=\r
124  a widget.\r
125 Calls to renderers should be done asynchronously, so that displaying large =\r
126 threads\r
127 does not block the interface unnecessarily.\r
128 The text representation should be stored in a way that can be incrementally=\r
129  updated\r
130 for use with message parts decrypted at a later point.\r
131 \r
132 \r
133 Bad Solutions\r
134 -------------\r
135 \r
136 1. Current solution: walk the MIME-tree depth-first, use blocking calls to =\r
137 handlers\r
138 and create a fixed "body" string that is displayed in the widget.\r
139 A silly and hackish solution that we want to get rid of for obvious reasons.\r
140 \r
141 2. Use a "PartWidget" that is able to display a node in the MIME-tree:\r
142 Its constructor creates the representation in a RFC compliant way, that is,\r
143 it decodes 'text/plain' parts, stacks other widgets of the same kind on top=\r
144  of each other\r
145 for multipart parts or calls external renderer to get a text representation.\r
146 \r
147 Cons:\r
148  * widgets should not be clever and contain/construct any kind of additiona=\r
149 l info\r
150  * its hard to update these widgets when a part gets decrypted; =\r
151 \r
152  * decrypted parts are not available outside the displaying widget, widgets=\r
153  get\r
154    replaced completely when one rebuilds the buffer (refresh cmd)\r
155 Pros:\r
156  * we can use Deferreds relatively painlessly in the ui (as opposed to the =\r
157 db-wrapper)\r
158 \r
159 3. Accumulate rendered text in a tree structure *inside* message-objects an=\r
160 d let that\r
161 massage update the widget that displays it. One could let the widget regist=\r
162 er\r
163 some update-callback with the widget that rebuilds the widgets content.\r
164 These callbacks are called after the external handler has finished and the =\r
165 message-\r
166 internal text-representation has been updated.\r
167 \r
168 Pros: =\r
169 \r
170  * rendered text/decrypted message parts end up in the message and are avai=\r
171 lable to process\r
172    and redisplay at will\r
173 Cons:\r
174  * the calls to MIME-handlers are dealt with as Deferreds which depend on t=\r
175 he twisted event\r
176    loop and indirectly on urwid. This is exactly the kind of tight coupling=\r
177  I'm trying to avoid:\r
178    Messages should be independent of the interface.\r
179  * Messages with multiple externally rendered parts will rebuild their widg=\r
180 ets more than once\r
181  * references to old widgets (replaced e.g. after a buffer rebuild) will be=\r
182  kept, which keeps\r
183    them from being garbage-collected\r
184 \r
185 I'm surely missing an easy and elegant solution here.\r
186 Any pointers or comments are much appreciated.\r
187 Thanks,\r
188 /p\r
189 \r
190 \r
191 [0]: http://alot.readthedocs.org/en/latest/api/database.html\r
192 [1]: http://excess.org/urwid/\r
193 [2]: http://twistedmatrix.com/documents/current/core/howto/defer.html\r
194 [3]: http://docs.python.org/library/email\r