From: Thomas Roessler Date: Thu, 27 Aug 1998 23:45:40 +0000 (+0000) Subject: [patch-0.94.4.vikas.collapse.2] Vikas' collapse-thread X-Git-Tag: mutt-0-94-5i-rel~15 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a56c4be859b9138d8f7044aaf5c72bbb7ad821cc;p=mutt [patch-0.94.4.vikas.collapse.2] Vikas' collapse-thread patch. --- diff --git a/OPS b/OPS index 39282f6d..6979d615 100644 --- a/OPS +++ b/OPS @@ -144,3 +144,5 @@ OP_VERSION "show the Mutt version number and date" OP_VIEW_ATTACH "view attachment using mailcap entry if necessary" OP_VIEW_ATTACHMENTS "show MIME attachments" OP_MAIN_SHOW_LIMIT "show currently active limit pattern" +OP_MAIN_COLLAPSE_THREAD "collapse/uncollapse current thread" +OP_MAIN_COLLAPSE_ALL "collapse/uncollapse all threads" diff --git a/curs_main.c b/curs_main.c index 401a18b7..ef87bcf6 100644 --- a/curs_main.c +++ b/curs_main.c @@ -69,6 +69,7 @@ #define CURHDR Context->hdrs[Context->v2r[menu->current]] #define OLDHDR Context->hdrs[Context->v2r[menu->oldcurrent]] +#define UNREAD(h) mutt_thread_contains_unread (Context, h) extern const char *ReleaseDate; @@ -124,7 +125,7 @@ void index_make_entry (char *s, size_t l, MUTTMENU *menu, int num) } } - _mutt_make_string (s, l, NONULL (HdrFmt), Context, h, flag); + _mutt_make_string (s, l, NONULL (HdrFmt), Context, h, flag | M_FORMAT_INDEX); } int index_color (int index_no) @@ -267,13 +268,14 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */) if (Context && !attach_msg) { + int check; /* check for new mail in the mailbox. If nonzero, then something has * changed about the file (either we got new mail or the file was * modified underneath us.) */ index_hint = (Context->vcount) ? CURHDR->index : 0; - if ((i = mx_check_mailbox (Context, &index_hint)) < 0) + if ((check = mx_check_mailbox (Context, &index_hint)) < 0) { if (!Context->path) { @@ -284,8 +286,10 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */) set_option (OPTSEARCHINVALID); } - else if (i == M_NEW_MAIL || i == M_REOPENED) + else if (check == M_NEW_MAIL || check == M_REOPENED) { + int *save_new; + /* take note of the current message */ if (oldcount) { @@ -300,32 +304,75 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */) * they will be visible in the limited view */ if (Context->pattern) { - #define this_body Context->hdrs[i]->content - if (oldcount) - for (i = oldcount; i < Context->msgcount; i++) +#define THIS_BODY Context->hdrs[j]->content + if (oldcount || check == M_REOPENED) + for (j = (check == M_REOPENED) ? 0 : oldcount; j < Context->msgcount; j++) { if (mutt_pattern_exec (Context->limit_pattern, M_MATCH_FULL_ADDRESS, - Context, Context->hdrs[i])) + Context, Context->hdrs[j])) { - Context->hdrs[i]->virtual = Context->vcount; - Context->v2r[Context->vcount] = i; - Context->vcount++; - Context->vsize+=this_body->length + this_body->offset - - this_body->hdr_offset; + Context->hdrs[j]->virtual = Context->vcount; + Context->v2r[Context->vcount] = j; + Context->hdrs[j]->limited = 1; + Context->vcount++; + Context->vsize += THIS_BODY->length + THIS_BODY->offset - THIS_BODY->hdr_offset; } } - #undef this_body +#undef THIS_BODY + } + + /* save the list of new messages */ + if (oldcount && check != M_REOPENED) + { + save_new = (int *) safe_malloc (sizeof (int) * (Context->msgcount - oldcount)); + for (j = oldcount; j < Context->msgcount; j++) + save_new[j-oldcount] = Context->hdrs[j]->index; } /* if the mailbox was reopened, need to rethread from scratch */ - mutt_sort_headers (Context, (i == M_REOPENED)); + set_option (OPTSORTCOLLAPSE); + mutt_sort_headers (Context, (check == M_REOPENED)); + unset_option (OPTSORTCOLLAPSE); + + /* uncollapse threads with new mail */ + if ((Sort & SORT_MASK) == SORT_THREADS) + { + if (check == M_REOPENED) + { + HEADER *h; + + h = Context->tree; + Context->collapsed = 0; + + while (h) + { + mutt_uncollapse_thread (Context, h); + h = h->next; + } + mutt_set_virtual (Context); + } + else if (oldcount) + { + for (j = 0; j < Context->msgcount - oldcount; j++) + { + int k; + + for (k = 0; k < Context->msgcount; k++) + { + HEADER *h = Context->hdrs[k]; + if (h->index == save_new[j] && (!Context->pattern || h->limited)) + mutt_uncollapse_thread (Context, h); + } + } + FREE (&save_new); + mutt_set_virtual (Context); + } + } menu->current = -1; if (oldcount) { - int j; - /* restore the current message to the message it was pointing to */ for (j = 0; j < Context->vcount; j++) if (Context->hdrs[Context->v2r[j]]->index == menu->oldcurrent) @@ -339,7 +386,7 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */) menu->current = ci_first_message (); /* notify the user of new mail */ - if (i == M_REOPENED) + if (check == M_REOPENED) mutt_error ("Mailbox was externally modified. Flags may be wrong."); else { @@ -882,7 +929,14 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */) toggle_option (OPTWEED); unset_option (OPTNEEDRESORT); - + if ((Sort & SORT_MASK) == SORT_THREADS && CURHDR->collapsed) + { + mutt_uncollapse_thread (Context, CURHDR); + mutt_set_virtual (Context); + if (option (OPTUNCOLLAPSEJUMPNEW)) + menu->current = mutt_thread_next_new (Context, CURHDR); + } + if ((op = mutt_display_message (CURHDR, attach_msg_status)) == -1) { unset_option (OPTNEEDRESORT); @@ -1045,6 +1099,7 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */) menu->current = -1; for (j = 0; j != Context->vcount; j++) { +#define CUR Context->hdrs[Context->v2r[i]] if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_NEXT_UNREAD) { i++; @@ -1064,22 +1119,25 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */) } } - if (! Context->hdrs[Context->v2r[i]]->deleted && - ! Context->hdrs[Context->v2r[i]]->read) + if ((!CUR->deleted && !CUR->read) || + (CUR->collapsed && !CUR->deleted && UNREAD (CUR))) { if (op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD || - ! Context->hdrs[Context->v2r[i]]->old) + !CUR->old) { menu->current = i; break; } } } +#undef CUR if (menu->current == -1) { + char *tmp = ""; menu->current = menu->oldcurrent; - mutt_error ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW) ? - "No new messages." : "No unread messages."); + if (Context->pattern) + tmp = " in this limited view"; + mutt_error ("%s%s.", (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW) ? "No new messages" : "No unread messages", NONULL (tmp)); } else if (menu->menu == MENU_PAGER) { @@ -1227,6 +1285,81 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */) } break; + case OP_MAIN_COLLAPSE_THREAD: + CHECK_MSGCOUNT; + + if (CURHDR->collapsed) + { + menu->current = mutt_uncollapse_thread (Context, CURHDR); + mutt_set_virtual (Context); + if (option (OPTUNCOLLAPSEJUMPNEW)) + menu->current = mutt_thread_next_new (Context, CURHDR); + } + else if (option (OPTCOLLAPSENEW) || !UNREAD (CURHDR)) + { + menu->current = mutt_collapse_thread (Context, CURHDR); + mutt_set_virtual (Context); + } + else + { + mutt_error ("Thread contains unread messages."); + break; + } + + menu->redraw = REDRAW_INDEX | REDRAW_STATUS; + + break; + + case OP_MAIN_COLLAPSE_ALL: + CHECK_MSGCOUNT; + + if ((Sort & SORT_MASK) != SORT_THREADS) + { + mutt_error ("Threading is not enabled."); + break; + } + + { + HEADER *h, *base; + int final; + + if (CURHDR->collapsed) + final = mutt_uncollapse_thread (Context, CURHDR); + else if (option (OPTCOLLAPSENEW) || !UNREAD (CURHDR)) + final = mutt_collapse_thread (Context, CURHDR); + else + final = CURHDR->virtual; + + base = Context->hdrs[Context->v2r[final]]; + + h = Context->tree; + Context->collapsed = !Context->collapsed; + while (h) + { + if (h->collapsed != Context->collapsed) + { + if (h->collapsed) + mutt_uncollapse_thread (Context, h); + else if (option (OPTCOLLAPSENEW) || !UNREAD (h)) + mutt_collapse_thread (Context, h); + } + h = h->next; + } + + mutt_set_virtual (Context); + for (j = 0; j < Context->vcount; j++) + { + if (Context->hdrs[Context->v2r[j]]->index == base->index) + { + menu->current = j; + break; + } + } + + menu->redraw = REDRAW_INDEX | REDRAW_STATUS; + break; + } + /* -------------------------------------------------------------------- * These functions are invoked directly from the internal-pager */ diff --git a/functions.h b/functions.h index 7877f3e2..9579ec7c 100644 --- a/functions.h +++ b/functions.h @@ -68,6 +68,8 @@ struct binding_t OpMain[] = { { "bounce-message", OP_BOUNCE_MESSAGE, "b" }, { "change-folder", OP_MAIN_CHANGE_FOLDER, "c" }, { "change-folder-readonly", OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" }, + { "collapse-thread", OP_MAIN_COLLAPSE_THREAD, "\033v" }, + { "collapse-all", OP_MAIN_COLLAPSE_ALL, "\033V" }, { "copy-message", OP_COPY_MESSAGE, "C" }, { "decode-copy", OP_DECODE_COPY, "\033C" }, { "decode-save", OP_DECODE_SAVE, "\033s" }, diff --git a/hdrline.c b/hdrline.c index 2e9710b9..c5b5fd6a 100644 --- a/hdrline.c +++ b/hdrline.c @@ -18,7 +18,7 @@ #include "mutt.h" #include "mutt_curses.h" - +#include "sort.h" #ifdef _PGPPATH @@ -224,6 +224,9 @@ hdr_format_str (char *dest, char fmt[SHORT_STRING], buf2[SHORT_STRING], ch, *p; int do_locales, i; int optional = (flags & M_FORMAT_OPTIONAL); + int threads = ((Sort & SORT_MASK) == SORT_THREADS); + int is_index = (flags & M_FORMAT_INDEX); +#define NEW (threads && hdr->collapsed && hdr->num_hidden > 1 && mutt_thread_contains_unread (ctx, hdr)) size_t len; hdr = hfi->hdr; @@ -446,22 +449,22 @@ hdr_format_str (char *dest, break; case 's': - snprintf (fmt, sizeof (fmt), "%%%ss", prefix); - if (flags & M_FORMAT_TREE) + + snprintf (fmt, sizeof (fmt), "%s%%%ss", threads && is_index ? " " : "", prefix); + if (threads && is_index && hdr->collapsed && hdr->num_hidden > 1) + snprintf (dest, destlen, "%2d %s", hdr->num_hidden, NONULL(hdr->env->subject)); + else if (flags & M_FORMAT_TREE) { if (flags & M_FORMAT_FORCESUBJ) { - snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree, - hdr->env->subject ? hdr->env->subject : ""); + snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree, NONULL (hdr->env->subject)); snprintf (dest, destlen, fmt, buf2); } else snprintf (dest, destlen, fmt, hdr->tree); } else - { - snprintf (dest, destlen, fmt, hdr->env->subject ? hdr->env->subject : ""); - } + snprintf (dest, destlen, fmt, NONULL (hdr->env->subject)); break; case 'S': @@ -544,7 +547,7 @@ hdr_format_str (char *dest, snprintf (buf2, sizeof (buf2), "%c%c%c", (hdr->read && (ctx && ctx->msgnotreadyet != hdr->msgno)) - ? (hdr->replied ? 'r' : ' ') : (hdr->old ? 'O' : 'N'), + ? (NEW ? 'n' : (hdr->replied ? 'r' : ' ')) : (hdr->old ? 'O' : (NEW ? 'n' : 'N')), hdr->deleted ? 'D' : (hdr->attach_del ? 'd' : ch), hdr->tagged ? '*' : (hdr->flagged ? '!' : @@ -563,6 +566,7 @@ hdr_format_str (char *dest, mutt_FormatString (dest, destlen, elsestring, hdr_format_str, (unsigned long) hfi, flags); return (src); +#undef NEW } void diff --git a/init.h b/init.h index 397a8237..0ffadfe6 100644 --- a/init.h +++ b/init.h @@ -87,6 +87,9 @@ struct option_t MuttVars[] = { { "beep_new", DT_BOOL, R_NONE, OPTBEEPNEW, 0 }, { "charset", DT_STR, R_NONE, UL &Charset, UL "iso-8859-1" }, { "check_new", DT_BOOL, R_NONE, OPTCHECKNEW, 1 }, + { "collapse_new", DT_BOOL, R_NONE, OPTCOLLAPSENEW, 1 }, + { "uncollapse_jump_new", DT_BOOL, R_NONE, OPTUNCOLLAPSEJUMPNEW, 0 }, + { "auto_collapse", DT_BOOL, R_NONE, OPTAUTOCOLLAPSE, 0 }, { "confirmappend", DT_BOOL, R_NONE, OPTCONFIRMAPPEND, 1 }, { "confirmcreate", DT_BOOL, R_NONE, OPTCONFIRMCREATE, 1 }, { "copy", DT_QUAD, R_NONE, OPT_COPY, M_YES }, diff --git a/mbox.c b/mbox.c index edae95fd..d5ef5f56 100644 --- a/mbox.c +++ b/mbox.c @@ -649,7 +649,9 @@ int mbox_sync_mailbox (CONTEXT *ctx) { save_sort = Sort; Sort = SORT_ORDER; + set_option (OPTSORTCOLLAPSE); mutt_sort_headers (ctx, 0); + unset_option (OPTSORTCOLLAPSE); } /* need to open the file for writing in such a way that it does not truncate @@ -890,7 +892,9 @@ bail: /* Come here in case of disaster */ Sort = save_sort; /* if the mailbox was reopened, the thread tree will be invalid so make * sure to start threading from scratch. */ + set_option (OPTSORTCOLLAPSE); mutt_sort_headers (ctx, (need_sort == M_REOPENED)); + unset_option (OPTSORTCOLLAPSE); } return (-1); diff --git a/mutt.h b/mutt.h index d68f60ad..96160306 100644 --- a/mutt.h +++ b/mutt.h @@ -100,7 +100,8 @@ typedef enum M_FORMAT_MAKEPRINT = (1<<2), /* make sure that all chars are printable */ M_FORMAT_OPTIONAL = (1<<3), M_FORMAT_STAT_FILE = (1<<4), /* used by mutt_attach_fmt */ - M_FORMAT_ARROWCURSOR = (1<<5) /* reserve space for arrow_cursor */ + M_FORMAT_ARROWCURSOR = (1<<5), /* reserve space for arrow_cursor */ + M_FORMAT_INDEX = (1<<6) /* this is a main index entry */ } format_flag; /* types for mutt_add_hook() */ @@ -123,6 +124,12 @@ typedef enum #define M_TREE_HIDDEN 9 #define M_TREE_MAX 10 +#define M_THREAD_COLLAPSE (1<<0) +#define M_THREAD_UNCOLLAPSE (1<<1) +#define M_THREAD_GET_HIDDEN (1<<2) +#define M_THREAD_UNREAD (1<<3) +#define M_THREAD_NEXT_NEW (1<<4) + enum { /* modes for mutt_view_attachment() */ @@ -236,11 +243,13 @@ enum OPTASKBCC, OPTASKCC, OPTATTACHSPLIT, + OPTAUTOCOLLAPSE, OPTAUTOEDIT, OPTAUTOTAG, OPTBEEP, OPTBEEPNEW, OPTCHECKNEW, + OPTCOLLAPSENEW, OPTCONFIRMAPPEND, OPTCONFIRMCREATE, OPTEDITHDRS, @@ -280,6 +289,7 @@ enum OPTSUSPEND, OPTTHOROUGHSRC, OPTTILDE, + OPTUNCOLLAPSEJUMPNEW, OPTUSE8BITMIME, OPTUSEDOMAIN, OPTUSEFROM, @@ -288,7 +298,7 @@ enum OPTWRAP, OPTWRAPSEARCH, OPTWRITEBCC, /* write out a bcc header? */ - + /* PGP options */ #ifdef _PGPPATH @@ -318,6 +328,7 @@ enum OPTFORCEREDRAWPAGER, /* (pseudo) used to force a redraw in the pager */ OPTSORTSUBTHREADS, /* (pseudo) used when $sort_aux changes */ OPTNEEDRESCORE, /* (pseudo) set when the `score' command is used */ + OPTSORTCOLLAPSE, /* (pseudo) used by mutt_sort_headers() */ #ifdef _PGPPATH OPTPGPCHECKTRUST, /* (pseudo) used by pgp_select_key () */ @@ -502,6 +513,11 @@ typedef struct header unsigned int searched : 1; unsigned int matched : 1; + /* the following are used to support collapsing threads */ + unsigned int collapsed : 1; /* is this message part of a collapsed thread? */ + unsigned int limited : 1; /* is this message in a limited view? */ + size_t num_hidden; /* number of hidden messages in this view */ + int pair; /* color-pair to use when displaying in the index */ time_t date_sent; /* time when the message was sent (UTC) */ @@ -583,6 +599,7 @@ typedef struct unsigned int setgid : 1; unsigned int quiet : 1; /* inhibit status messages? */ unsigned int revsort : 1; /* mailbox sorted in reverse? */ + unsigned int collapsed : 1; /* are all threads collapsed? */ } CONTEXT; typedef struct attachptr diff --git a/mx.c b/mx.c index ce611617..3e05a4f1 100644 --- a/mx.c +++ b/mx.c @@ -540,6 +540,7 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx) ctx->path = safe_strdup (path); ctx->msgnotreadyet = -1; + ctx->collapsed = 0; if (flags & M_QUIET) ctx->quiet = 1; @@ -956,7 +957,9 @@ int mx_sync_mailbox (CONTEXT *ctx) #undef this_body ctx->msgcount = j; + set_option (OPTSORTCOLLAPSE); mutt_sort_headers (ctx, 1); /* rethread from scratch */ + unset_option (OPTSORTCOLLAPSE); } return (rc); diff --git a/pattern.c b/pattern.c index 2b6d857c..53b85d47 100644 --- a/pattern.c +++ b/pattern.c @@ -899,12 +899,18 @@ int mutt_pattern_func (int op, char *prompt) if (op == M_LIMIT) { for (i = 0; i < Context->msgcount; i++) + { Context->hdrs[i]->virtual = -1; + Context->hdrs[i]->limited = 0; + Context->hdrs[i]->collapsed = 0; + Context->hdrs[i]->num_hidden = 0; + } Context->vcount = 0; Context->vsize = 0; + Context->collapsed = 0; } -#define this_body Context->hdrs[i]->content +#define THIS_BODY Context->hdrs[i]->content for (i = 0; i < Context->msgcount; i++) if (mutt_pattern_exec (pat, M_MATCH_FULL_ADDRESS, Context, Context->hdrs[i])) @@ -925,19 +931,21 @@ int mutt_pattern_func (int op, char *prompt) break; case M_LIMIT: Context->hdrs[i]->virtual = Context->vcount; + Context->hdrs[i]->limited = 1; Context->v2r[Context->vcount] = i; Context->vcount++; - Context->vsize+=this_body->length + this_body->offset - - this_body->hdr_offset; + Context->vsize+=THIS_BODY->length + THIS_BODY->offset - + THIS_BODY->hdr_offset; break; } } -#undef this_body +#undef THIS_BODY mutt_clear_error (); if (op == M_LIMIT) { + Context->collapsed = 0; safe_free ((void **) &Context->pattern); if (Context->limit_pattern) mutt_pattern_free (&Context->limit_pattern); @@ -948,6 +956,9 @@ int mutt_pattern_func (int op, char *prompt) for (i = 0; i < Context->msgcount; i++) { Context->hdrs[i]->virtual = i; + Context->hdrs[i]->limited = 0; + Context->hdrs[i]->num_hidden = 0; + Context->hdrs[i]->collapsed = 0; Context->v2r[i] = i; } diff --git a/protos.h b/protos.h index 9a9ed0b6..43b45508 100644 --- a/protos.h +++ b/protos.h @@ -46,6 +46,13 @@ int _mutt_system (const char *, int); #define mutt_previous_subthread(x) _mutt_aside_thread(x,0,1) int _mutt_aside_thread (HEADER *, short, short); +#define mutt_collapse_thread(x,y) _mutt_traverse_thread (x,y,M_THREAD_COLLAPSE) +#define mutt_uncollapse_thread(x,y) _mutt_traverse_thread (x,y,M_THREAD_UNCOLLAPSE) +#define mutt_get_hidden(x,y)_mutt_traverse_thread (x,y,M_THREAD_GET_HIDDEN) +#define mutt_thread_contains_unread(x,y) _mutt_traverse_thread (x,y,M_THREAD_UNREAD) +#define mutt_thread_next_new(x,y) _mutt_traverse_thread(x,y,M_THREAD_NEXT_NEW) +int _mutt_traverse_thread (CONTEXT *ctx, HEADER *hdr, int flag); + #define ISSPACE(c) isspace((unsigned char)c) #define mutt_new_parameter() safe_calloc (1, sizeof (PARAMETER)) @@ -123,7 +130,7 @@ void mutt_block_signals_system (void); void mutt_body_handler (BODY *, STATE *); void mutt_bounce_message (HEADER *, ADDRESS *); void mutt_buffy (char *); -void mutt_check_rescore (CONTEXT *ctx); +void mutt_check_rescore (CONTEXT *); void mutt_clear_error (void); void mutt_create_alias (ENVELOPE *, ADDRESS *); void mutt_decode_attachment (BODY *, STATE *); @@ -185,6 +192,7 @@ void mutt_update_encoding (BODY *a); void mutt_update_tree (ATTACHPTR **, short); void mutt_version (void); void mutt_view_attachments (HEADER *); +void mutt_set_virtual (CONTEXT *); int mutt_addr_is_user (ADDRESS *); int mutt_alias_complete (char *, size_t); diff --git a/sort.c b/sort.c index 3ece2f7f..292435e5 100644 --- a/sort.c +++ b/sort.c @@ -176,6 +176,7 @@ void mutt_sort_headers (CONTEXT *ctx, int init) { int i; sort_t *sortfunc; + int collapse = (option (OPTSORTCOLLAPSE)) ? 0 : 1; unset_option (OPTNEEDRESORT); @@ -236,15 +237,21 @@ void mutt_sort_headers (CONTEXT *ctx, int init) /* adjust the virtual message numbers */ ctx->vcount = 0; + if (collapse) + ctx->collapsed = 0; for (i = 0; i < ctx->msgcount; i++) { - if (ctx->hdrs[i]->virtual != -1) + HEADER *cur = ctx->hdrs[i]; + if (cur->virtual != -1 || (collapse && cur->collapsed && (!ctx->pattern || cur->limited))) { - ctx->hdrs[i]->virtual = ctx->vcount; + cur->virtual = ctx->vcount; ctx->v2r[ctx->vcount] = i; ctx->vcount++; } - ctx->hdrs[i]->msgno = i; + cur->msgno = i; + cur->num_hidden = mutt_get_hidden (ctx, cur); + if (collapse) + cur->collapsed = 0; } mutt_cache_index_colors(ctx); diff --git a/thread.c b/thread.c index 8336e91d..12d85b99 100644 --- a/thread.c +++ b/thread.c @@ -17,7 +17,18 @@ */ #include "mutt.h" +#include "mutt_curses.h" +#include "mutt_menu.h" #include "sort.h" +#include "mailbox.h" +#include "copy.h" +#include "mx.h" +#include +#include + +#ifdef BUFFY_SIZE +#include "buffy.h" +#endif #include #include @@ -38,7 +49,7 @@ static HEADER *find_reference (HEADER *cur, CONTEXT *ctx) } /* Determines whether to display a message's subject. */ -static int need_display_subject (HEADER *tree) +static int need_display_subject (CONTEXT *ctx, HEADER *tree) { HEADER *tmp; @@ -46,7 +57,7 @@ static int need_display_subject (HEADER *tree) return (1); for (tmp = tree->prev; tmp; tmp = tmp->prev) { - if (tmp->virtual >= 0) + if (tmp->virtual >= 0 || (tmp->collapsed && (!ctx->pattern || tmp->limited))) { if (!tmp->subject_changed) return (0); @@ -56,7 +67,7 @@ static int need_display_subject (HEADER *tree) } for (tmp = tree->parent; tmp; tmp = tmp->parent) { - if (tmp->virtual >= 0) + if (tmp->virtual >= 0 || (tmp->collapsed && (!ctx->pattern || tmp->limited))) return (0); else if (tmp->subject_changed) return (1); @@ -66,7 +77,7 @@ static int need_display_subject (HEADER *tree) /* determines whether a later sibling or the child of a later sibling is displayed. */ -int is_next_displayed (HEADER *tree) +static int is_next_displayed (CONTEXT *ctx, HEADER *tree) { int depth = 0; @@ -75,7 +86,7 @@ int is_next_displayed (HEADER *tree) FOREVER { - if (tree->virtual >= 0) + if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited))) return (1); if (tree->child) @@ -122,8 +133,8 @@ void mutt_linearize_tree (CONTEXT *ctx, int linearize) FOREVER { - if (tree->virtual >= 0) - tree->display_subject = need_display_subject (tree); + if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited))) + tree->display_subject = need_display_subject (ctx, tree); if (depth >= max_depth) safe_realloc ((void **) &pfx, @@ -136,26 +147,26 @@ void mutt_linearize_tree (CONTEXT *ctx, int linearize) safe_free ((void **) &tree->tree); if (!depth) { - if (tree->virtual >= 0) + if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited))) tree->tree = safe_strdup (""); } else { myarrow = arrow + (depth - start_depth - (start_depth ? 0 : 1)) * 2; - nextdisp = is_next_displayed (tree); + nextdisp = is_next_displayed (ctx, tree); if (depth && start_depth == depth) myarrow[0] = nextdisp ? M_TREE_LTEE : corner; else myarrow[0] = M_TREE_HIDDEN; myarrow[1] = tree->fake_thread ? M_TREE_STAR : M_TREE_HLINE; - if (tree->virtual >= 0) + if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited))) { myarrow[2] = M_TREE_RARROW; myarrow[3] = 0; } - if (tree->virtual >= 0) + if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited))) { tree->tree = safe_malloc ((2 + depth * 2) * sizeof (char)); if (start_depth > 1) @@ -184,7 +195,7 @@ void mutt_linearize_tree (CONTEXT *ctx, int linearize) mypfx[1] = M_TREE_SPACE; } depth++; - if (tree->virtual >= 0) + if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited))) start_depth = depth; tree = tree->child; } @@ -192,14 +203,14 @@ void mutt_linearize_tree (CONTEXT *ctx, int linearize) { while (!tree->next && tree->parent) { - if (tree->virtual >= 0) + if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited))) start_depth = depth; tree = tree->parent; if (start_depth == depth) start_depth--; depth--; } - if (tree->virtual >= 0) + if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited))) start_depth = depth; if ((tree = tree->next) == NULL) break; @@ -671,3 +682,166 @@ int _mutt_aside_thread (HEADER *hdr, short dir, short subthreads) return (tmp->virtual); } + +void mutt_set_virtual (CONTEXT *ctx) +{ + int i; + + ctx->vcount = 0; + ctx->vsize = 0; + +#define THIS_BODY cur->content + for (i = 0; i < ctx->msgcount; i++) + { + HEADER *cur = ctx->hdrs[i]; + if (cur->virtual != -1) + { + cur->virtual = ctx->vcount; + ctx->v2r[ctx->vcount] = i; + ctx->vcount++; + ctx->vsize += THIS_BODY->length + THIS_BODY->offset - THIS_BODY->hdr_offset; + cur->num_hidden = mutt_get_hidden (ctx, cur); + } + } +#undef THIS_BODY +} + +int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag) +{ + HEADER *roothdr = NULL, *top; + int final, reverse = (Sort & SORT_REVERSE), minmsgno; + int num_hidden = 0, unread = 0; + int min_unread_msgno = INT_MAX, min_unread = cur->virtual; +#define CHECK_LIMIT (!ctx->pattern || cur->limited) + + if ((Sort & SORT_MASK) != SORT_THREADS && !(flag & M_THREAD_GET_HIDDEN)) + { + mutt_error ("Threading is not enabled."); + return (cur->virtual); + } + + final = cur->virtual; + while (cur->parent) + cur = cur->parent; + top = cur; + minmsgno = cur->msgno; + + + if (!cur->read && CHECK_LIMIT) + { + unread = 1; + if (cur->msgno < min_unread_msgno) + { + min_unread = cur->virtual; + min_unread_msgno = cur->msgno; + } + } + + if (cur->virtual == -1 && CHECK_LIMIT) + num_hidden++; + + if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) + { + cur->collapsed = flag & M_THREAD_COLLAPSE; + if (cur->virtual != -1) + { + roothdr = cur; + if (flag & M_THREAD_COLLAPSE) + final = roothdr->virtual; + } + } + + if ((cur = cur->child) == NULL) + { + /* return value depends on action requested */ + if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) + return (final); + else if (flag & M_THREAD_UNREAD) + return (unread); + else if (flag & M_THREAD_GET_HIDDEN) + return (num_hidden); + else if (flag & M_THREAD_NEXT_NEW) + return (min_unread); + } + + FOREVER + { + if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) + { + cur->collapsed = flag & M_THREAD_COLLAPSE; + if (!roothdr && CHECK_LIMIT) + { + roothdr = cur; + if (flag & M_THREAD_COLLAPSE) + final = roothdr->virtual; + } + + if (reverse && (flag & M_THREAD_COLLAPSE) && (cur->msgno < minmsgno) + && CHECK_LIMIT) + { + minmsgno = cur->msgno; + final = cur->virtual; + } + + if (flag & M_THREAD_COLLAPSE) + { + if (cur != roothdr) + cur->virtual = -1; + } + else + { + if (CHECK_LIMIT) + cur->virtual = cur->msgno; + } + } + + + if (!cur->read && CHECK_LIMIT) + { + unread = 1; + if (cur->msgno < min_unread_msgno) + { + min_unread = cur->virtual; + min_unread_msgno = cur->msgno; + } + } + + if (cur->virtual == -1 && CHECK_LIMIT) + num_hidden++; + + if (cur->child) + cur = cur->child; + else if (cur->next) + cur = cur->next; + else + { + int done = 0; + while (!cur->next) + { + cur = cur->parent; + if (cur == top) + { + done = 1; + break; + } + } + if (done) + break; + cur = cur->next; + } + } + + /* return value depends on action requested */ + if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) + return (final); + else if (flag & M_THREAD_UNREAD) + return (unread); + else if (flag & M_THREAD_GET_HIDDEN) + return (num_hidden+1); + else if (flag & M_THREAD_NEXT_NEW) + return (min_unread); + + return (0); +#undef CHECK_LIMIT +} +