From ad6ad6f8dd1254e7126d675a97500c61c0e456bd Mon Sep 17 00:00:00 2001 From: Patrick Totzke Date: Wed, 21 Mar 2012 09:07:22 +0000 Subject: [PATCH] [RFC][alot] design decisions --- b6/68bc6939f83d62b9ad4c365df8a4ea676ec316 | 194 ++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 b6/68bc6939f83d62b9ad4c365df8a4ea676ec316 diff --git a/b6/68bc6939f83d62b9ad4c365df8a4ea676ec316 b/b6/68bc6939f83d62b9ad4c365df8a4ea676ec316 new file mode 100644 index 000000000..82a1a2cdd --- /dev/null +++ b/b6/68bc6939f83d62b9ad4c365df8a4ea676ec316 @@ -0,0 +1,194 @@ +Return-Path: +X-Original-To: notmuch@notmuchmail.org +Delivered-To: notmuch@notmuchmail.org +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 -- 2.26.2