<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en">
<head>
  <title>the all-thing</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <link rel="stylesheet" href="/static/style.css" type="text/css" />
  <link rel="alternate" type="application/rss+xml" title="the all-thing RSS feed" href="/index.rss" />
  <link rel="alternate" type="text/plain" title="the all-thing in plain text" href="/index.txt" />
  <script type="text/javascript" src="/static/mootools.js"></script>
  <script type="text/javascript" src="http://music.masanjin.net:9292/waxiest.js"></script>
</head>
<body>

<div id="main">
  <div id="header">
    <h1><a  href="/">the all-thing</a></h1>
    
      <p>Showing only posts labeled "sup" (<a  href="/label/sup.rss">rss</a>). <a  href="/index/">See all posts</a>.</p>
    
  </div>
  <div id="sidebar">
    <h3>Recent comments</h3>

    <ul class="sidebar-list">
    
    <li><b><a  href="/whisper-0.5#58174069c046a78e55f02ef81da81e74">Dominique Julia</a></b>
        <i><a  href="/whisper-0.5">Whisper 0.5 released</a></i>
           one week ago
    </li>
    
    <li><b><a  href="/ruby-ncurses-and-thread-blocking#8fa2a0f392d7c0562d630e4936407c11">William Morgan</a></b>
        <i><a  href="/ruby-ncurses-and-thread-blocking">Ruby, Ncurses and blocked threads</a></i>
           three months ago
    </li>
    
    <li><b><a  href="/git-wtf-bf06ab7-released#533654a7a229569e27a6d0afd716c444">William Morgan</a></b>
        <i><a  href="/git-wtf-bf06ab7-released">git wtf bf06ab7 released</a></i>
           three months ago
    </li>
    
    <li><b><a  href="/git-wtf-bf06ab7-released#b7b7a905477674eb6985b34a964a0dca">Joao Nelas</a></b>
        <i><a  href="/git-wtf-bf06ab7-released">git wtf bf06ab7 released</a></i>
           three months ago
    </li>
    
    <li><b><a  href="/ruby-ncurses-and-thread-blocking#b00001114360ac152f87d4ac2a6e0c5b">Ollivier Robert</a></b>
        <i><a  href="/ruby-ncurses-and-thread-blocking">Ruby, Ncurses and blocked threads</a></i>
           three months ago
    </li>
    
    </ul>

    <h3>Authors</h3>
    <ul class="sidebar-list">
    
      <li><a class="author" href="/by/William+Morgan/">William&nbsp;Morgan</a>&nbsp;(65) </li>
    
    </ul>

    <h3>Tags</h3>
    <ul class="sidebar-list">
    
      <li><a class="label" href="/label/releases/">releases</a>&nbsp;(15) </li>
    
      <li><a class="label" href="/label/whisper/">whisper</a>&nbsp;(13) </li>
    
      <li><a class="label" href="/label/git/">git</a>&nbsp;(9) </li>
    
      <li><a class="label" href="/label/stats/">stats</a>&nbsp;(8) </li>
    
      <li><a class="label" href="/label/trollop/">trollop</a>&nbsp;(6) </li>
    
      <li><a class="label" href="/label/ruby/">ruby</a>&nbsp;(6) </li>
    
      <li><a class="label" href="/label/sup/">sup</a>&nbsp;(6) </li>
    
      <li><a class="label" href="/label/git-wtf/">git-wtf</a>&nbsp;(4) </li>
    
      <li><a class="label" href="/label/vm/">vm</a>&nbsp;(4) </li>
    
      <li><a class="label" href="/label/mathml/">mathml</a>&nbsp;(3) </li>
    
      <li><a class="label" href="/label/continuations/">continuations</a>&nbsp;(3) </li>
    
      <li><a class="label" href="/label/ditz/">ditz</a>&nbsp;(3) </li>
    
      <li><a class="label" href="/label/proglang/">proglang</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/optimization/">optimization</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/benchmarks/">benchmarks</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/rubinius/">rubinius</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/inlining/">inlining</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/ubuntu/">ubuntu</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/fibers/">fibers</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/ritex/">ritex</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/ruby1.9/">ruby1.9</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/ncurses/">ncurses</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/javascript/">javascript</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/media/">media</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/vim/">vim</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/classification/">classification</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/massachusetts/">massachusetts</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/greasemonkey/">greasemonkey</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/wine/">wine</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/readme/">readme</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/ancient-greek/">ancient-greek</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/web/">web</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/current+events/">current&nbsp;events</a>&nbsp;(1) </li>
    
    </ul>

    <h3>Other formats</h3>
    <ul class="sidebar-list">
    <li><a href="/index.rss"><img src="/static/rss-badge.png"/></a></li>
    <li><a href="/index.txt">plain text version</a></li>
    </ul>

    <h3 class="waxiest.author.original">Who is this man?</h3>
    <h3 class="waxiest.author.beautiful" style="display:none">I must find out more about this beautiful creature</h3>
    <h3 class="waxiest.author.beautifulbig" style="display:none">I MUST FIND OUT MORE ABOUT THIS BEAUTIFUL CREATURE</h3>
    <h3 class="waxiest.author.originalbig" style="display:none">WHO IS THIS MAN?</h3>

    <script type="text/javascript">
      var w = waxiest();
      w.optimizeHTMLSection("author", ["original", "beautiful", "beautifulbig", "originalbig"]);
    </script>

    <a href="http://masanjin.net" onClick="w.goalReached('greeting')">William Morgan</a>
  </div>
  <div id="content">
    
  <h2><a  href="/ruby-ncurses-and-thread-blocking">Ruby, Ncurses and blocked threads</a></h2>
  <div class="byline">
    <a  href="/by/William+Morgan/">William Morgan</a>,
    <span title="7 months ago">August  6, 2009  6:40pm</span>
  </div>
  
    <div class="labels"><span class='label'><a  href="/label/ruby/">ruby</a></span> <span class='label'><a  href="/label/ncurses/">ncurses</a></span> <span class='label'><a  href="/label/sup/">sup</a></span> </div>
  
  <p class='first'>If you&#8217;re writing a multithreaded Ruby program that uses ncurses,
you might be curious why program stops running when you call
<code>Ncurses.getch</code>. <a href="http://sup.rubyforge.org">Sup</a> has been plagued
by this issue since 2005. Thankfully, I think I finally understand
it.</p>
<p>The problem is that there is a bug in the Ruby ncurses library
such that using blocking input will block <strong>all</strong> Ruby threads when
it waits for user input, instead of just the calling thread. So
<code>Ncurses.getch</code> will cause everything to grind to a halt.  This is
probably due to the library not releasing the <span class="caps">GVL</span> when blocking on
stdin.</p>
<p>This bug is present in the latest rubygems version of curses,
0.9.1. It has been fixed in the latest libncurses-ruby Debian
packages (1.1-3).</p>
<p>To see if you have a buggy, blocking version of the ruby ncurses
library, run this program:</p>
<p><code><pre class="ruby"><span class="ident">require</span> <span class="punct">'</span><span class="string">rubygems</span><span class="punct">'</span>
<span class="ident">require</span> <span class="punct">'</span><span class="string">ncurses</span><span class="punct">'</span>
<span class="ident">require</span> <span class="punct">'</span><span class="string">thread</span><span class="punct">'</span>

<span class="constant">Ncurses</span><span class="punct">.</span><span class="ident">initscr</span>
<span class="constant">Ncurses</span><span class="punct">.</span><span class="ident">noecho</span>
<span class="constant">Ncurses</span><span class="punct">.</span><span class="ident">cbreak</span>
<span class="constant">Ncurses</span><span class="punct">.</span><span class="ident">curs_set</span> <span class="number">0</span>

<span class="constant">Thread</span><span class="punct">.</span><span class="ident">new</span> <span class="keyword">do</span>
  <span class="ident">sleep</span> <span class="number">0.1</span>
  <span class="constant">Ncurses</span><span class="punct">.</span><span class="ident">stdscr</span><span class="punct">.</span><span class="ident">mvaddstr</span> <span class="number">0</span><span class="punct">,</span> <span class="number">0</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">library is GOOD.</span><span class="punct">&quot;</span>
<span class="keyword">end</span>

<span class="keyword">begin</span>
  <span class="constant">Ncurses</span><span class="punct">.</span><span class="ident">stdscr</span><span class="punct">.</span><span class="ident">mvaddstr</span> <span class="number">0</span><span class="punct">,</span> <span class="number">0</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">library is BAD.</span><span class="punct">&quot;</span>
  <span class="constant">Ncurses</span><span class="punct">.</span><span class="ident">getch</span>
<span class="keyword">ensure</span>
  <span class="constant">Ncurses</span><span class="punct">.</span><span class="ident">curs_set</span> <span class="number">1</span>
  <span class="constant">Ncurses</span><span class="punct">.</span><span class="ident">endwin</span>
  <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">bye</span><span class="punct">&quot;</span>
<span class="keyword">end</span></pre></code></p>
<p>(I purposely require <code>rubygems</code> in there to load the rubygems
ncurses library if it&#8217;s present; you can drop this if you don&#8217;t
use rubygems.)</p>
<p>There are two workarounds to this problem. First, you can simply
tell ncurses to use nonblocking input:</p>
<p><code><pre class="ruby"><span class="constant">Ncurses</span><span class="punct">.</span><span class="ident">nodelay</span> <span class="constant">Ncurses</span><span class="punct">.</span><span class="ident">stdscr</span><span class="punct">,</span> <span class="constant">true</span></pre></code></p>
<p>But if you&#8217;re writing a multithreaded app, you probably aren&#8217;t
interested in nonblocking input, unless you want a nasty polling
loop.</p>
<p>The better choice is to add a call to <code>IO.select</code> before <code>getch</code>,
which will block the calling thread until there&#8217;s an actual
keypress, and then allow <code>getch</code> to pick it up:</p>
<p><code><pre class="ruby"><span class="keyword">if</span> <span class="constant">IO</span><span class="punct">.</span><span class="ident">select</span> <span class="punct">[</span><span class="global">$stdin</span><span class="punct">],</span> <span class="constant">nil</span><span class="punct">,</span> <span class="constant">nil</span><span class="punct">,</span> <span class="number">1</span>
  <span class="constant">Ncurses</span><span class="punct">.</span><span class="ident">getch</span>
<span class="keyword">end</span></pre></code></p>
<p><code>IO.select</code> requires a delay, so you&#8217;ll have to handle the
periodic nils that generates. But the background threads should no longer block.</p>
<p>There is one further complication, which is that you won&#8217;t be able
to receive the pseudo-keypresses Ncurses emits when the terminal
size changes, since they don&#8217;t show up on <code>$stdin</code> and thus the
<code>select</code> won&#8217;t pass. The solution is to install your own signal
handler:</p>
<p><code><pre class="ruby"><span class="ident">trap</span><span class="punct">(&quot;</span><span class="string">WINCH</span><span class="punct">&quot;)</span> <span class="punct">{</span> <span class="punct">...</span> <span class="ident">handle</span> <span class="ident">sigwinch</span>  <span class="punct">...</span> <span class="punct">}</span></pre></code></p>
<p>You will still see the resize events coming from <code>getch</code>, but only
once the user presses a key. You can drop them at this point.</p>
<p>That should be enough to make any multithreaded Ruby ncurses app
able function. Of course, once everyone&#8217;s using a fixed version fo
the ncurses libraries, you can do away with the <code>select</code> and set
<code>nodelay</code> to false.</p>
<p>(One last hint for the future: I&#8217;ve found it necessary to set it
to false before every call to <code>getch</code>; otherwise a ctrl-c will
magically change it back to nonblocking mode. Not sure why.)</p>
  <div class="comment-link">
    
    <a  href="/ruby-ncurses-and-thread-blocking#comments">Three comments by <b>Ollivier Robert</b>, <b>Felipe Contreras</b>, and one other</a>.
  </div>

  <h2><a  href="/sup-next">What&#8217;s cooking in Sup next</a></h2>
  <div class="byline">
    <a  href="/by/William+Morgan/">William Morgan</a>,
    <span title="11 months ago">March 25, 2009 12:51pm</span>
  </div>
  
    <div class="labels"><span class='label'><a  href="/label/sup/">sup</a></span> </div>
  
  <p class='first'>The 0.7 release ain&#8217;t the only exciting <a href="http://sup.rubyforge.org/">Sup</a> news.
Here&#8217;s a list of interesting features that are currently cooking in Sup next,
along with the associated branch name.</p>
<ul>
	<li>zsh completion for sup commandline commands, thanks to Ingmar
  Vanhassel. (<em>zsh-completion</em>)</li>
</ul>
<ul>
	<li>Undo support for many commands, thanks to Mike Stipicevic.
  (<em>undo-manager</em>)</li>
</ul>
<ul>
	<li>You can now remove labels from multiple tagged threads, thanks to
  Nicolas Pouillard, using the syntax <code>-label</code>). (<em>multi-remove-labels</em>)</li>
</ul>
<ul>
	<li>Sup works on terminals with transparent backgrounds (and that&#8217;s fixed
  copy-and-paste for me too!), thanks to Mark Alexander.
  (<em>default-colors</em>)</li>
</ul>
<ul>
	<li>Pressing &#8216;b&#8217; now lets you roll buffers both forward and backward,
  also thanks to Nicolas Pouillard. (<em>roll-buffers</em>)</li>
</ul>
<ul>
	<li>Duplicate messages (including messages you send to a mailing list, and
  then receive a copy of) should now have their labels merged, except
  for unread and inbox labels. So if you automatically label messages
  from mailing lists via the before-add-hook, that should work better
  for you now. (<em>merge-labels</em>)</li>
</ul>
<ul>
	<li>Saving message state is now backgrounded, so pressing &#8216;$&#8217; after
  reading a big thread shouldn&#8217;t interfere with your life. It still
  blocks when closing a buffer, though, so I have to make that work.
  (<em>background-save</em>)</li>
</ul>
<ul>
	<li>Email canonicalization, also thanks to Nicolas Pouillard. The mapping
  between email addresses and names is no longer maintained across multiple
  emails. (<em>dont-canonicalize-email-addresses</em>)</li>
</ul>
<p>The canonicalization one is a weird one. There&#8217;s been a long-standing problem
in Sup where names associated with email addresses are saved and reused.
Unfortunately many automated systems like <span class="caps">JIRA</span>, evite, blogger, etc. will send
you email on behalf of someone else, using the same email address but different
names. The issue was compounded because Sup decided that longer names should
always replace shorter ones, so receiving some spam claiming to be from your
address but with a random name would have all sorts of crazy effects.</p>
<p>Addresses are still stored in the index, both for search purposes, and for
<code>thread-index-mode</code>. (Otherwise <code>thread-index-mode</code> has to reread the headers
from the message source, which is slow.) Once <code>thread-view-mode</code> is opened, the
headers must be read from the source anyways, so the email address is updated
to the correct version.</p>
<p>So, incoming new email should be fine. Sup will store whatever name is in the
headers, and won&#8217;t do any canonicalization.</p>
<p>For older email, you can update the index manually by viewing the message in
<code>thread-view-mode</code>, and forcing Sup to re-save it, e.g. by changing the labels
and then changing them back. Marking it as read, and then reading it, is an
easy way to accomplish this, at least for read messages.</p>
<p>You can also make judicious use of <code>sup-sync</code> to do this for all messages in
your index.</p>
  <div class="comment-link">
    
    <a  href="/sup-next#comments">No comments</a>.
  </div>

  <h2><a  href="/sup-0.7">Sup 0.7 released</a></h2>
  <div class="byline">
    <a  href="/by/William+Morgan/">William Morgan</a>,
    <span title="11 months ago">March 25, 2009 12:49pm</span>
  </div>
  
    <div class="labels"><span class='label'><a  href="/label/sup/">sup</a></span> <span class='label'><a  href="/label/releases/">releases</a></span> </div>
  
  <p class='first'>Sup 0.7 has been released.</p>
<p>You can read the announcement <a href="http://rubyforge.org/pipermail/sup-talk/2009-March/002030.html">here</a></p>
<p>The big win in this release is that Ferret index corruption issues
should now be fixed, thanks to an extensive programming of locking and
thread-safety-adding.</p>
<p>The other nice change is that text entry will now scroll to the right
upon overflow, thanks to some arcane Curses magic.</p>
  <div class="comment-link">
    
    <a  href="/sup-0.7#comments">Three comments by <b>William Morgan</b> and <b>Paul Tötterman</b></a>.
  </div>

  <h2><a  href="/git-conflict-resolution">Sharing Conflict Resolutions in Git</a></h2>
  <div class="byline">
    <a  href="/by/William+Morgan/">William Morgan</a>,
    <span title="11 months ago">March 22, 2009  5:23pm</span>
  </div>
  
    <div class="labels"><span class='label'><a  href="/label/git/">git</a></span> <span class='label'><a  href="/label/sup/">sup</a></span> </div>
  
  <p class='first'>Development of <a href="http://sup.rubyforge.org/">Sup</a> is done with Git. Sup follows a
<em>topic branch</em> methodology: features and bugfixes typically start off as
&#8220;topic&#8221; branches from <code>master</code>, and are merged into an &#8220;integration&#8221;/&#8220;version&#8221;
branch <code>next</code> for integration testing. After <em>n</em> cycles of additional bugfix
commits to the topic branch, and re-merges into <code>next</code>, the topic branches are
finally merged down to <code>master</code>, to be included in the next release.</p>
<p>I really like this approach because I think it evinces the real power of Git:
that merges are so foolproof that I can pick and choose, on a
feature-by-feature basis, which bits of code I want at each level of
integration. That&#8217;s crazy cool. And users can stick to <code>master</code> if they want
something stable, and <code>next</code> if they want the latest-and-greatest features.</p>
<p>The biggest problem I&#8217;ve had, though, is that long-lived topic branches often
conflict with each other. This happens both when merging into <code>next</code> and when
merging into <code>master</code>. I don&#8217;t think there&#8217;s a way around it; isolating
features in this way has all the benefits above, but it also means that when
they touch the same bits of code, you&#8217;ll get a conflict.</p>
<p>As a lazy maintainer, the biggest question I&#8217;ve had is: is there a way to push
the burden of conflict resolution to the patch submitter? Is there a way for me
to say: hey, your change conflicts with Bob&#8217;s. Can you resolve the conflict and
send it to me?</p>
<p>One option I&#8217;ve considered is to have contributors to publish not only their
feature branches, but their <code>next</code> branch as well. Assuming they aren&#8217;t mucking
about with their <code>next</code> branch otherwise, if it contains just the merge commit,
I can merge it into mine, and it should be a fast-forward that gets me the
merge commit, conflict resolution and all.</p>
<p>But I don&#8217;t like that idea because, in every other case, I&#8217;m merging in the
feature branches directly. Why should I suddenly start merging in <code>next</code> just
because you have a conflict?</p>
<p>Furthermore, Sup primarily receives email contributions via <code>git format-patch</code>,
and I do the dirty deed of sorting them into branches and merging things
around. Requiring everyone to host a git repo iff they produce a conflicting
patch seems silly. (And <code>git format-patch</code>, unfortunately, produces nothing for
merge commits, even if they have conflict resolution changes. Maybe there&#8217;s a
good reason for this, or maybe not. I&#8217;m not sure.)</p>
<p>After some effort, and some git-talk discussion, I have a solution. And no, it
doesn&#8217;t involve sharing <code>git-rerere</code> caches. (Which it seems that some people
do!)</p>
<p>For the contributor: once you have resolved the conflict, do a <code>git diff
HEAD^</code>. This will output the conflict resolution changes. Email that to the
maintainer along with your patch.</p>
<p>For the maintainer:
<code><pre class="ruby"><span class="global">$ </span><span class="ident">git</span> <span class="ident">checkout</span> <span class="keyword">next</span>
<span class="global">$ </span><span class="ident">git</span> <span class="ident">merge</span> <span class="punct">&lt;</span><span class="ident">offending</span> <span class="ident">branch</span><span class="punct">&gt;</span>
<span class="punct">[...</span> <span class="ident">you</span> <span class="ident">have</span> <span class="ident">a</span> <span class="ident">conflict</span><span class="punct">,</span> <span class="ident">yada</span> <span class="ident">yada</span> <span class="punct">...]</span>
<span class="global">$ </span><span class="ident">git</span> <span class="ident">checkout</span> <span class="keyword">next</span> <span class="punct">.</span>
<span class="global">$ </span><span class="ident">git</span> <span class="ident">apply</span> <span class="punct">--</span><span class="ident">index</span> <span class="punct">&lt;</span><span class="ident">resolution</span> <span class="ident">patch</span> <span class="ident">filename</span><span class="punct">&gt;</span>
<span class="global">$ </span><span class="ident">git</span> <span class="ident">commit</span></pre></code></p>
<p>Running <code>git merge</code> gets you to the point where you have a conflict. Running
<code>git checkout next .</code> sets your working directory to the state it was before
you merged. And <code>git apply</code> applies the resolution changes.</p>
<p>You lose authorship of the conflict resolution, but you can use <code>git commit
--author</code> to set it.</p>
<p>I think the ideal solution would be for <code>git format-patch</code> to produce something
usable in this case. I see some traffic on the Git list that suggests this is
being considered, so hopefully one day this rigmarole will not be necessary.</p>
  <div class="comment-link">
    
    <a  href="/git-conflict-resolution#comments">Four comments by <b>William Morgan</b>, <b>Brendan O'Connor</b>, and one other</a>.
  </div>

  <h2><a  href="/old13">Rethinking Sup part II</a></h2>
  <div class="byline">
    <a  href="/by/William+Morgan/">William Morgan</a>,
    <span title="19 months ago">July 20, 2008  1:58pm</span>
  </div>
  
    <div class="labels"><span class='label'><a  href="/label/sup/">sup</a></span> </div>
  
  <p class='first'>In <a href="http://all-thing.net/2008/06/rethinking-sup.html">Rethinking Sup part I</a>, I
concluded that Sup the <span class="caps">MUA</span> is an evolutionary dead end, and that the future
lies in Sup the Service (<span class="caps">STS</span>). But what does that mean?</p>
<p>One thing I want to make clear it does <em>not</em> mean is any abandonment of the Sup
curses UI. That particular &#8220;user experience&#8221; has been refined over the past few
years to become my ideal email interface. It would be silly to throw that away.</p>
<p>What <em>will</em> happen to the curses code is that it will become one client among
(hopefully) many. Once there&#8217;s a clear delineation between UI and backend, you
can make a UI choice independent of making a choice to use Sup in the first
place. You can run <code>sup-curses-client</code> if you want. Or you can build
a web interface, or an Openmoko interface. Working with ncurses has always been
the least enjoyable part of Sup, so maybe I&#8217;ll actually enjoy learning
Javascript.</p>
<p>What backend functionality will <span class="caps">STS</span> actually provide? If I were simply
reworking Sup into a client and a server, the obvious answer would be &#8220;a
searchable, labelable, threaded view of large amounts of email&#8221;.</p>
<p>But reworking Sup is a great time to extend its original goals. In particular,
I would love for <span class="caps">STS</span> to handle to other types of documents besides email. I&#8217;ve
always used my inbox as a mechanism for writing notes to myself. I&#8217;ve
experimented briefly with reading <span class="caps">RSS</span> feeds through it. I&#8217;d like <span class="caps">STS</span> to support
email, of course, but not to be limited by it.</p>
<p>My grand vision: <em><span class="caps">STS</span> will be a searchable, labelable, threaded view of large
numbers of documents.</em></p>
<p>You can throw whatever you want in there, and <span class="caps">STS</span> will store it, thread it, and
let you label and search for it. Email, <span class="caps">RSS</span> feeds, notes, jabber and <span class="caps">IRC</span> logs,
web pages, RI documents—I want you to be able to throw them all in there. I
want you to be able to annotate any of those things by adding notes and
threading them against the original objects. Basically I want <span class="caps">STS</span> to be the
primary tool you use for organizing and recalling all the textual information
you&#8217;ve ever encountered in your life.</p>
<p>Cool, huh?</p>
<p>There&#8217;s another convenient benefit to this transformation: no one will expect
<span class="caps">STS</span> to act like a <span class="caps">MUA</span>. <span class="caps">STS</span> does its own storage. You add your email and your
other documents to the server and then you can throw those files away (or not).
There are no more questions of supporting <span class="caps">IMAP</span> or various mbox dialects or &#8220;why
doesn&#8217;t Sup  treat Maildir correctly&#8221;. The files are in <span class="caps">STS</span>, and once they&#8217;re
their, they&#8217;re out of your hands. You&#8217;ll be able to export them, of course, and
if you&#8217;re crazy you might be able to write an <span class="caps">IMAP</span> <em>server</em> translation layer
for <span class="caps">STS</span>, but there will be no more expectation of realtime Maildir handling. As
I explained in part I, that&#8217;s a game I don&#8217;t want to play.</p>
<p><span class="caps">STS</span> is a grander vision than a <span class="caps">MUA</span>, and it no longer has to be hobbled by the
constraints of being expected to act like one.</p>
<p>Some other nice benefits of reworking Sup into <span class="caps">SYS</span>:</p>
<ul>
	<li>You&#8217;ll be able to run multiple clients at once.</li>
	<li>It&#8217;s an opportunity to rework some things. For example, one of the most
noticeably slow operations in Sup (&#8220;Classic&#8221;) is assembling a large thread.
This is because I made a decision early on to do all threading at search time.
That made certain things easier (in particular, I could change the threading
model without having to rescan the entire index), but in retrospect the cost is
too high. <span class="caps">STS</span> will maintain document trees directly.</li>
	<li>I can replace Ferret with Sphinx. It&#8217;s been a good couple years, but the
periodic non-deterministic index corruption that&#8217;s been an issue for <a href="http://ferret.davebalmain.com/trac/ticket/279">over a
year</a> is an exit sign to me.
Working with Sphinx is nowhere nearly as nice as working with Ferret, but speed
and stability go a long way.</li>
</ul>
<p>I&#8217;ve been working on the code for <span class="caps">STS</span> on and off for the past couple weeks and
it&#8217;s slowly starting to come together. Once the major components have at least
been all sketched, I will host a git repo.</p>
  <div class="comment-link">
    
    <a  href="/old13#comments">19 comments by <b>Graham Dunn</b>, <b>John</b>, and 10 others</a>.
  </div>

  <h2><a  href="/old25">Rethinking Sup</a></h2>
  <div class="byline">
    <a  href="/by/William+Morgan/">William Morgan</a>,
    <span title="20 months ago">June 24, 2008  8:37pm</span>
  </div>
  
    <div class="labels"><span class='label'><a  href="/label/sup/">sup</a></span> </div>
  
  <p class='first'>It&#8217;s been clear to me for a while now that Sup has been trying to be two very
different things at once, thus pleasing no one and irritating everyone. There&#8217;s
Sup the <em>email client</em>, which is kind of the standard view of things. And then
there&#8217;s Sup the <em>service</em>: a threaded, fielded, searchable, labelable view into
your email.</p>
<p>Sup the email client is lacking in many ways, as many people have been very
quick to point out to me. The most obvious of these is that it refuses to
actually, you know, actually write back any state to your mailstore.
Specifically, read/unread state is never written anywhere except its internal
index. Furthermore, mailstore rescans of most any type are incredibly slow.
These two features make using it in conjunction with other clients near
impossible, which pretty much breaks one of the primary  principles of tool
design: don&#8217;t break other tools. (Then there&#8217;s also the problem of <span class="caps">IMAP</span>
connections being terrifically slow and prone to crashes, but I lay most of
that blame on <span class="caps">IMAP</span> being a crappy protocol and the Ruby <span class="caps">IMAP</span> libraries leaving
a lot to be desired.)</p>
<p>Sup the service, on the other hand, suffers from the rather obvious flaw of not
being exposed in any manner other than through Sup itself (and irb, I suppose).</p>
<p>I think the reason for this bizarre situation stems from my goal of fusing two
very different things together: mutt and Gmail. Mutt is a client; Gmail is a
service; Sup cherry-picks functionality, and lack of functionality, from both.
Examples: I refused to have Sup write back to mailstores because Gmail didn&#8217;t
have to export to your local Maildir or mbox file, so why should I? (Well
technically, I said I would accept patches that did that, but that I wouldn&#8217;t
be working on that feature myself. A fine distinction!) At the same time, I
pooh-poohed the notion of a Sup server because mutt didn&#8217;t have a  server, and
so why should Sup? And so on.</p>
<p>For Sup to evolve into something more useful than it is, and that appeals to a
broader audience than it currently does, I believe it has to go down one of
these routes completely. And I believe I know which one, and I believe this can
be done without compromising the basic user experience, which I would be very
reluctant to do because it has been lovingly tweaked over the years to be
William&#8217;s Ideal Email Experience.</p>
<p>The first option is to make Sup more of a client. In order to be a real email
client, Sup must be able to interoperate with other clients. This means it has
to write back all its state to the mailstores: read/unread status in whatever
manner the mailstore supports, and probably something like all labels in a
special header. It must also be able to do a full rescan in a fast manner, so
that changes by other clients are reflected.</p>
<p>Right off the bat, that seems impossible, redundant with other software, and
not that interesting. As I wrote in a <a href="http://rubyforge.org/pipermail/sup-talk/2008-April/001456.html">sup-talk thread from a few months
ago</a>:</p>
<blockquote>
<p>Sup is never going to be able to compete with programs like Mutt in
terms of operations like &#8220;open up a mailstore of some format X, and mark a
bunch of messages as read, and move a bunch of messages to this other
mailstore.&#8221; That&#8217;s a tremendous amount of work to get right, get safe and get
fast, and Mutt&#8217;s already done it well, and I sure don&#8217;t want to have to
reimplement it.  Competing with mutt on grounds of speed, stability, and
breadth of Mailstore usage is a recipe for fail. Ruby sure as shit ain&#8217;t gonna
come close to C for speed (at least until Rubinius gets <span class="caps">LLVM</span> working), and
mutt&#8217;s already hammered out all the quirkinesses with Exchange, etc.</p>
</blockquote>
<p>But not only would it be impossible, it wouldn&#8217;t be interesting. The things
that make Sup valuable are the UI, the indexing and the flags, and those simple
don&#8217;t translate to external mailstores. Furthermore, Sup is aimed at the
mailstores of the future (my present mailstores), which are so big that mutt
can&#8217;t handle them anyways.</p>
<p>So that leaves Sup as a service. And that&#8217;s where things get interesting. But
I&#8217;ll save that for a later post.</p>
  <div class="comment-link">
    
    <a  href="/old25#comments">No comments</a>.
  </div>




  </div>

  <div id="footer" style="margin: 0px;">
    Served up by <a href="http://masanjin.net/whisper/">Whisper</a>. Yes!
  </div>
</div>
</body>
</html>
