From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by olra.theworths.org (Postfix) with ESMTP id 43591431FAF for ; Wed, 21 Mar 2012 02:07:28 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: -0.799 X-Spam-Level: X-Spam-Status: No, score=-0.799 tagged_above=-999 required=5 tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled Received: from olra.theworths.org ([127.0.0.1]) by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id QiFZfOGmUaQm for ; Wed, 21 Mar 2012 02:07:27 -0700 (PDT) Received: from mail-wi0-f179.google.com (mail-wi0-f179.google.com [209.85.212.179]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (No client certificate requested) by olra.theworths.org (Postfix) with ESMTPS id 3FCE7431FAE for ; Wed, 21 Mar 2012 02:07:27 -0700 (PDT) Received: by wibhn6 with SMTP id hn6so938225wib.2 for ; Wed, 21 Mar 2012 02:07:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20120113; h=content-type:mime-version:content-transfer-encoding:to:message-id :from:user-agent:subject:date; bh=fKKVWMfpPhBa+YjVOMkXNQETWGr8KdMJXHAPWEAg2V4=; b=zAnBO89XvQgv/sstFTsGIajSZSd79qBQCjSigiRSyHDyrvNZMQaZfyyoXwRU1STXvy w4kk1FwF0kwh60eLGO4Yz9RcCV7rfBIXsBJiIb7BSaty+a2wsYLTgkCgMU2ETPofnNvH 4TRh4In7/6MsWcws0B/ax1TQ0PujNFyCr+Wy3NU3FbJ1ivnM5lac2JBoNP3UJCD2hBLo rwsiJRqoXu8Co7QDoBtMqGOEGwUGssCHQxO5bvepKZ+yl/GOzNp9FD966Gwm/78DROxl N0iXc89Y3SvhJqWjIFhoFl98FpPLFP0zeYLzULGW/VLmtIpvpIcC/MPuN/BXF2+9yAbR XPww== Received: by 10.180.100.2 with SMTP id eu2mr7238366wib.1.1332320845915; Wed, 21 Mar 2012 02:07:25 -0700 (PDT) Received: from localhost (cpc1-sgyl2-0-0-cust548.18-2.cable.virginmedia.com. [82.41.10.37]) by mx.google.com with ESMTPS id e6sm2985347wix.8.2012.03.21.02.07.24 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 21 Mar 2012 02:07:24 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable To: Notmuch Mail Message-ID: <20120321090722.6892.24383@brick.lan> From: Patrick Totzke User-Agent: alot/0.3 Subject: [RFC][alot] design decisions Date: Wed, 21 Mar 2012 09:07:22 +0000 X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 21 Mar 2012 09:07:28 -0000 Hi all, with alot 0.3 released, I started thinking seriously about proper=E2=84=A2 = MIME-display and gnupg integration for alot. I have to make a few design decisions here and could = really use some informed opinions from more experienced UI developers. My question in = particular is: = How do I best integrate calls to external mime-handlers into my MVC event = driven code? I mostly know how to implement the individual parts but I struggle coming u= p with a consistent way of organizing it all without compromising my current layout. Background ---------- Model. Alot uses an abstraction layer over notmuch's thread, message and da= tabase objects to make them less fragile and generally behave more OOP-y: You can e.g. dir= ectly call message.add_tags(['foo','bar']) and so on. This is made possible by a "Data= baseManager" that maintains centralized and queued access to the notmuch index and deals= with notmuch exceptions like a locked index [0]. View/Controler. We use an event-driven interface (urwid.TwistedEventLoop, [= 1]) that handles user input and maintains a tree of widgets that knows how to render= itself. Twisted offers a neat concept of "Deferreds" to organize call- and errbacks= that we already make use of [2]. Alot has a "MessageWidget" that displays a single= message. We can easily access and parse email messages into MIME-trees (msg.get_emai= l() returns a email.message object; pythons email module allows extensive and RFC complia= nt dealing with this [3]). We already offer full compatibility with the mailcap protocol to constuct s= hell commands of external MIME handlers. We know how to call external commands asynchronously; `alot.helper.call_cmd= _async` does this and returns a Deferred to which we can connect callback functions. Objective --------- We want to turn a email.message into nicely rendered text and display it as= a widget. Calls to renderers should be done asynchronously, so that displaying large = threads does not block the interface unnecessarily. The text representation should be stored in a way that can be incrementally= updated for use with message parts decrypted at a later point. Bad Solutions ------------- 1. Current solution: walk the MIME-tree depth-first, use blocking calls to = handlers and create a fixed "body" string that is displayed in the widget. A silly and hackish solution that we want to get rid of for obvious reasons. 2. Use a "PartWidget" that is able to display a node in the MIME-tree: Its constructor creates the representation in a RFC compliant way, that is, it decodes 'text/plain' parts, stacks other widgets of the same kind on top= of each other for multipart parts or calls external renderer to get a text representation. Cons: * widgets should not be clever and contain/construct any kind of additiona= l info * its hard to update these widgets when a part gets decrypted; = * decrypted parts are not available outside the displaying widget, widgets= get replaced completely when one rebuilds the buffer (refresh cmd) Pros: * we can use Deferreds relatively painlessly in the ui (as opposed to the = db-wrapper) 3. Accumulate rendered text in a tree structure *inside* message-objects an= d let that massage update the widget that displays it. One could let the widget regist= er some update-callback with the widget that rebuilds the widgets content. These callbacks are called after the external handler has finished and the = message- internal text-representation has been updated. Pros: = * rendered text/decrypted message parts end up in the message and are avai= lable to process and redisplay at will Cons: * the calls to MIME-handlers are dealt with as Deferreds which depend on t= he twisted event loop and indirectly on urwid. This is exactly the kind of tight coupling= I'm trying to avoid: Messages should be independent of the interface. * Messages with multiple externally rendered parts will rebuild their widg= ets more than once * references to old widgets (replaced e.g. after a buffer rebuild) will be= kept, which keeps them from being garbage-collected I'm surely missing an easy and elegant solution here. Any pointers or comments are much appreciated. Thanks, /p [0]: http://alot.readthedocs.org/en/latest/api/database.html [1]: http://excess.org/urwid/ [2]: http://twistedmatrix.com/documents/current/core/howto/defer.html [3]: http://docs.python.org/library/email