]> granicus.if.org Git - mutt/commitdiff
Threading enhancements from Daniel Eisenbud.
authorThomas Roessler <roessler@does-not-exist.org>
Thu, 28 Feb 2002 07:58:56 +0000 (07:58 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Thu, 28 Feb 2002 07:58:56 +0000 (07:58 +0000)
init.h
mutt.h
thread.c

diff --git a/init.h b/init.h
index 564ca1a505bfd0eb32ba6183e46233786a750c39..754318696c0a9b434506f021729f69e8bda4a97f 100644 (file)
--- a/init.h
+++ b/init.h
@@ -663,12 +663,31 @@ struct option_t MuttVars[] = {
   ** affect the generation of Message-IDs, and it will not lead to the 
   ** cut-off of first-level domains.
   */
+  { "hide_limited",    DT_BOOL, R_RESORT|R_INDEX, OPTHIDELIMITED, 0 },
+  /*
+  ** .pp
+  ** When set, mutt will not show the presence of missing messages in the
+  ** thread tree.
+  */
   { "hide_missing",    DT_BOOL, R_RESORT|R_INDEX, OPTHIDEMISSING, 1 },
   /*
   ** .pp
-  ** When set, mutt will not indicate the presence of missing messages
-  ** whose ancestors neither have siblings nor are in the current mailbox,
-  ** in the thread tree.
+  ** When set, mutt will not show the presence of messages that are hidden
+  ** by limiting, in the thread tree.
+  */
+  { "hide_top_limited",        DT_BOOL, R_RESORT|R_INDEX, OPTHIDETOPLIMITED, 0 },
+  /*
+  ** .pp
+  ** When set, mutt will not show the presence of missing messages at the
+  ** top of threads in the thread tree.  Note that when $$hide_limited is
+  ** set, this option will have no effect.
+  */
+  { "hide_top_missing",        DT_BOOL, R_RESORT|R_INDEX, OPTHIDETOPMISSING, 1 },
+  /*
+  ** .pp
+  ** When set, mutt will not show the presence of messages that are hidden
+  ** by limiting, at the top of threads in the thread tree.Note that when
+  ** $$hide_missing is set, this option will have no effect.
   */
   { "history",         DT_NUM,  R_NONE, UL &HistSize, 10 },
   /*
diff --git a/mutt.h b/mutt.h
index b8e2df4c5f87e7470e10022bbdaab28e6812a4c8..b380b3e575b3158312702f66eda1cfb239d2bcd2 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -341,7 +341,10 @@ enum
   OPTHEADER,
   OPTHELP,
   OPTHIDDENHOST,
+  OPTHIDELIMITED,
   OPTHIDEMISSING,
+  OPTHIDETOPLIMITED,
+  OPTHIDETOPMISSING,
   OPTIGNORELISTREPLYTO,
 #ifdef USE_IMAP
   OPTIMAPLSUB,
@@ -700,6 +703,10 @@ typedef struct thread
   unsigned int duplicate_thread : 1;
   unsigned int sort_children : 1;
   unsigned int check_subject : 1;
+  unsigned int visible : 1;
+  unsigned int deep : 1;
+  unsigned int subtree_visible : 2;
+  unsigned int next_subtree_visible : 1;
   struct thread *parent;
   struct thread *child;
   struct thread *next;
index a43067c32b19d5f85e333c9c19215ee80be6f047..7e0ced860e5378a22fda88f1b8b12a4db69ceb94 100644 (file)
--- a/thread.c
+++ b/thread.c
@@ -77,42 +77,6 @@ static int need_display_subject (CONTEXT *ctx, HEADER *hdr)
   return (1);
 }
 
-/* determines whether a later sibling or the child of a later 
- * sibling is displayed.  
- */
-static int is_next_displayed (CONTEXT *ctx, THREAD *tree)
-{
-  int depth = 0;
-  HEADER *hdr;
-
-  if ((tree = tree->next) == NULL)
-    return (0);
-
-  FOREVER
-  {
-    hdr = tree->message;
-    if (hdr && VISIBLE (hdr, ctx))
-      return (1);
-
-    if (tree->child)
-    {
-      tree = tree->child;
-      depth++;
-    }
-    else
-    {
-      while (!tree->next && depth > 0)
-      {
-       tree = tree->parent;
-       depth--;
-      }
-      if ((tree = tree->next) == NULL)
-       break;
-    }
-  }
-  return (0);
-}
-
 static void linearize_tree (CONTEXT *ctx)
 {
   THREAD *tree = ctx->tree;
@@ -144,6 +108,104 @@ static void linearize_tree (CONTEXT *ctx)
   }
 }
 
+/* this calculates whether a node is the root of a subtree that has visible
+ * nodes, whether a node itself is visible, whether, if invisible, it has
+ * depth anyway, and whether any of its later siblings are roots of visible
+ * subtrees.  while it's at it, it frees the old thread display, so we can
+ * skip parts of the tree in mutt_draw_tree() if we've decided here that we
+ * don't care about them any more.
+ */
+static void calculate_visibility (CONTEXT *ctx)
+{
+  THREAD *tmp, *tree = ctx->tree;
+  int hide_top_missing = option (OPTHIDETOPMISSING) && !option (OPTHIDEMISSING);
+  int hide_top_limited = option (OPTHIDETOPLIMITED) && !option (OPTHIDELIMITED);
+
+  /* we walk each level backwards to make it easier to compute next_subtree_visible */
+  while (tree->next)
+    tree = tree->next;
+
+  FOREVER
+  {
+    tree->subtree_visible = 0;
+    if (tree->message)
+    {
+      safe_free ((void **) &tree->message->tree);
+      if (VISIBLE (tree->message, ctx))
+      {
+       tree->deep = 1;
+       tree->visible = 1;
+       tree->message->display_subject = need_display_subject (ctx, tree->message);
+       for (tmp = tree; tmp; tmp = tmp->parent)
+       {
+         if (tmp->subtree_visible)
+         {
+           tmp->deep = 1;
+           tmp->subtree_visible = 2;
+           break;
+         }
+         else
+           tmp->subtree_visible = 1;
+       }
+      }
+      else
+      {
+       tree->visible = 0;
+       tree->deep = !option (OPTHIDELIMITED);
+      }
+    }
+    else
+    {
+      tree->visible = 0;
+      tree->deep = !option (OPTHIDEMISSING);
+    }
+    tree->next_subtree_visible = tree->next && (tree->next->next_subtree_visible
+                                               || tree->next->subtree_visible);
+    if (tree->child)
+    {
+      tree = tree->child;
+      while (tree->next)
+       tree = tree->next;
+    }
+    else if (tree->prev)
+      tree = tree->prev;
+    else
+    {
+      while (tree && !tree->prev)
+       tree = tree->parent;
+      if (!tree)
+       break;
+      else
+       tree = tree->prev;
+    }
+  }
+  
+  /* now fix up for the OPTHIDETOP* options if necessary */
+  if (hide_top_limited || hide_top_missing)
+  {
+    tree = ctx->tree;
+    FOREVER
+    {
+      if (!tree->visible && tree->deep && tree->subtree_visible < 2 
+         && ((tree->message && hide_top_limited) || (!tree->message && hide_top_missing)))
+       tree->deep = 0;
+      if (!tree->deep && tree->child && tree->subtree_visible)
+       tree = tree->child;
+      else if (tree->next)
+       tree = tree->next;
+      else
+      {
+       while (tree && !tree->next)
+         tree = tree->parent;
+       if (!tree)
+         break;
+       else
+         tree = tree->next;
+      }
+    }
+  }
+}
+
 /* Since the graphics characters have a value >255, I have to resort to
  * using escape sequences to pass the information to print_enriched_string().
  * These are the macros M_TREE_* defined in mutt.h.
@@ -158,53 +220,39 @@ void mutt_draw_tree (CONTEXT *ctx)
   char corner = (Sort & SORT_REVERSE) ? M_TREE_ULCORNER : M_TREE_LLCORNER;
   char vtee = (Sort & SORT_REVERSE) ? M_TREE_BTEE : M_TREE_TTEE;
   int depth = 0, start_depth = 0, max_depth = 0, max_width = 0;
-  int nextdisp = 0, visible, pseudo = 0, hidden = 0;
-  THREAD *tree = ctx->tree;
+  THREAD *nextdisp = NULL, *pseudo = NULL, *parent = NULL, *tree = ctx->tree;
   HEADER *hdr;
 
+  /* Do the visibility calculations and free the old thread chars.
+   * From now on we can simply ignore invisible subtrees
+   */
+  calculate_visibility (ctx);
   while (tree)
   {
     if (depth >= max_depth)
       safe_realloc ((void **) &pfx,
                    (max_depth += 32) * 2 * sizeof (char));
-
     if (depth - start_depth >= max_width)
       safe_realloc ((void **) &arrow,
                    (max_width += 16) * 2 * sizeof (char));
-
     hdr = tree->message;
-
-    if (hdr)
-    {
-      if ((visible = VISIBLE (hdr, ctx)) !=  0)
-       hdr->display_subject = need_display_subject (ctx, hdr);
-      else hidden = 1;
-
-      safe_free ((void **) &hdr->tree);
-    }
-    else
-      visible = 0;
-
     if (depth)
     {
       myarrow = arrow + (depth - start_depth - (start_depth ? 0 : 1)) * 2;
-      
       if (depth && start_depth == depth)
        myarrow[0] = nextdisp ? M_TREE_LTEE : corner;
-      else if (tree->parent->message)
+      else if (parent->message && !option (OPTHIDELIMITED))
        myarrow[0] = M_TREE_HIDDEN;
-      else if (option (OPTHIDEMISSING))
-       myarrow[0] = nextdisp ? vtee : M_TREE_HLINE;
-      else
+      else if (!parent->message && !option (OPTHIDEMISSING))
        myarrow[0] = M_TREE_MISSING;
+      else
+       myarrow[0] = vtee;
       myarrow[1] = pseudo ?  M_TREE_STAR
                    : (tree->duplicate_thread ? M_TREE_EQUALS : M_TREE_HLINE);
-
-      if (visible)
+      if (tree->visible)
       {
        myarrow[2] = M_TREE_RARROW;
        myarrow[3] = 0;
-
        hdr->tree = safe_malloc ((2 + depth * 2) * sizeof (char));
        if (start_depth > 1)
        {
@@ -216,69 +264,66 @@ void mutt_draw_tree (CONTEXT *ctx)
          strfcpy (hdr->tree, arrow, 2 + depth * 2);
       }
     }
-
     if (tree->child && depth)
     {
       mypfx = pfx + (depth - 1) * 2;
       mypfx[0] = nextdisp ? M_TREE_VLINE : M_TREE_SPACE;
       mypfx[1] = M_TREE_SPACE;
     }
-
-    nextdisp = 0;
-    pseudo = 0;
-    hidden = 0;
-
+    parent = tree;
+    nextdisp = NULL;
+    pseudo = NULL;
     do
     {
-      if (tree->child)
+      if (tree->child && tree->subtree_visible)
       {
-       if (hdr || !option (OPTHIDEMISSING) || tree->child->next)
-       {
+       if (tree->deep)
          depth++;
-         if (visible)
-           start_depth = depth;
-         else
-           hidden = 1;
-       }
-
+       if (tree->visible)
+         start_depth = depth;
        tree = tree->child;
-       if (tree->fake_thread)
-         pseudo = 1;
-       if (depth && !nextdisp)
-         nextdisp = is_next_displayed (ctx, tree);
-       hdr = tree->message;
+
+       /* we do this here because we need to make sure that the first child thread
+        * of the old tree that we deal with is actually displayed if any are,
+        * or we might set the parent variable wrong while going through it. */
+       while (!tree->subtree_visible && tree->next)
+         tree = tree->next;
       }
       else
       {
        while (!tree->next && tree->parent)
        {
-         if (hdr && VISIBLE (hdr, ctx))
+         if (tree == pseudo)
+           pseudo = NULL;
+         if (tree == nextdisp)
+           nextdisp = NULL;
+         if (tree->visible)
            start_depth = depth;
-
          tree = tree->parent;
-         hdr = tree->message;
-
-         if (hdr || !option (OPTHIDEMISSING) || tree->child->next)
+         if (tree->deep)
          {
            if (start_depth == depth)
              start_depth--;
            depth--;
          }
        }
-
-       if (hdr && VISIBLE (hdr, ctx))
+       if (tree == pseudo)
+         pseudo = NULL;
+       if (tree == nextdisp)
+         nextdisp = NULL;
+       if (tree->visible)
          start_depth = depth;
        tree = tree->next;
        if (!tree)
          break;
-       if (tree->fake_thread)
-         pseudo = 1;
-       if (depth && !nextdisp)
-         nextdisp = is_next_displayed (ctx, tree);
-       hdr = tree->message;
       }
+      hdr = tree->message;
+      if (!pseudo && tree->fake_thread)
+       pseudo = tree;
+      if (!nextdisp && tree->next_subtree_visible)
+       nextdisp = tree;
     }
-    while (!(hdr || !option (OPTHIDEMISSING) || tree->child->next));
+    while (!tree->deep);
   }
 
   safe_free ((void **) &pfx);