From: Bernard 'Guyzmo' Pratz Date: Mon, 2 Jan 2017 00:42:58 +0000 (+0100) Subject: Searching with a window over notmuch vfolders X-Git-Tag: neomutt-20170113~8 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=426f0c27b1e3a0458405c87b7a0270f451f49bea;p=neomutt Searching with a window over notmuch vfolders When searching over a very large result, the result will be very slow for mutt to load. So, inspired by sup's feature to iteratively load the results, I figured adding a couple of commands to move an user set window backward/forward in time could be useful. And a new command extending the default vfolder-from-query function is being exposed. The current window information is user settable, so the user can make a macro that would do useful stuff about a search (like moving the window's position around, or further tweaking current search). * addition of four configuration variables, the first two are aimed at configuring the behaviour of the feature, the last two are exposing internals to make it hacking friendly: - nm_query_window_duration: duration for each window - nm_query_window_timebase: time base for each window - nm_query_window_current_search: the search being displayed as vfolder - nm_query_window_current_position: the current window's position * addition of three bindable commands: - windowed-vfolder-from-query: execute a search with a window applied - windowed-vfolder-backward: move the window backwards in time - windowed-vfolder-forward: move the window forwards in time Closes: #278 --- diff --git a/OPS.NOTMUCH b/OPS.NOTMUCH index 4508e4e2b..7fdbe7fb4 100644 --- a/OPS.NOTMUCH +++ b/OPS.NOTMUCH @@ -1,5 +1,8 @@ OP_MAIN_CHANGE_VFOLDER "open a different virtual folder" OP_MAIN_VFOLDER_FROM_QUERY "generate virtual folder from query" +OP_MAIN_WINDOWED_VFOLDER_FROM_QUERY "generate virtual folder from query and time window" +OP_MAIN_WINDOWED_VFOLDER_FORWARD "shifts virtual folder time window forwards" +OP_MAIN_WINDOWED_VFOLDER_BACKWARD "shifts virtual folder time window backwards" OP_MAIN_MODIFY_LABELS "modify (notmuch) tags" OP_MAIN_MODIFY_LABELS_THEN_HIDE "modify labels and then hide message" OP_MAIN_ENTIRE_THREAD "read entire thread of the current message" diff --git a/curs_main.c b/curs_main.c index 5c35d8453..9bcb52ad7 100644 --- a/curs_main.c +++ b/curs_main.c @@ -1888,6 +1888,81 @@ int mutt_index_menu (void) main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint, 0); break; + case OP_MAIN_WINDOWED_VFOLDER_FROM_QUERY: + dprint(2, (debugfile, "OP_MAIN_WINDOWED_VFOLDER_FROM_QUERY\n")); + if (NotmuchQueryWindowDuration < 0) + { + mutt_message (_("Windowed queries disabled.")); + break; + } + if (!nm_query_window_check_timebase(NotmuchQueryWindowTimebase)) + { + mutt_message (_("Invalid nm_query_window_timebase value (valid values are: hour, day, week, month or year).")); + break; + } + buf[0] = '\0'; + if ((mutt_get_field ("Query: ", buf, sizeof (buf), MUTT_NM_QUERY) != 0) || !buf[0]) + { + mutt_message (_("No query, aborting.")); + break; + } + nm_setup_windowed_query(buf, sizeof (buf)); + nm_query_window_reset(); + if (!nm_uri_from_windowed_query(Context, buf, sizeof(buf), NotmuchQueryWindowTimebase, NotmuchQueryWindowDuration)) + mutt_message (_("Failed to create query, aborting.")); + else + { + dprint(2, (debugfile, "nm: windowed query (%s)\n", buf)); + main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint, 0); + } + break; + + case OP_MAIN_WINDOWED_VFOLDER_BACKWARD: + dprint(2, (debugfile, "OP_MAIN_WINDOWED_VFOLDER_BACKWARD\n")); + if (NotmuchQueryWindowDuration < 0) + { + mutt_message (_("Windowed queries disabled.")); + break; + } + if (!nm_query_window_check_timebase(NotmuchQueryWindowTimebase)) + { + mutt_message (_("Invalid nm_query_window_timebase value (valid values are: hour, day, week, month or year).")); + break; + } + buf[0] = '\0'; + nm_query_window_backward(); + if (!nm_uri_from_windowed_query(Context, buf, sizeof(buf), NotmuchQueryWindowTimebase, NotmuchQueryWindowDuration)) + mutt_message (_("Failed to create query, aborting.")); + else + { + dprint(2, (debugfile, "nm: - windowed query (%s)\n", buf)); + main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint, 0); + } + break; + + case OP_MAIN_WINDOWED_VFOLDER_FORWARD: + dprint(2, (debugfile, "OP_MAIN_WINDOWED_VFOLDER_FORWARD\n")); + if (NotmuchQueryWindowDuration < 0) + { + mutt_message (_("Windowed queries disabled.")); + break; + } + if (!nm_query_window_check_timebase(NotmuchQueryWindowTimebase)) + { + mutt_message (_("Invalid nm_query_window_timebase value (valid values are: hour, day, week, month or year).")); + break; + } + buf[0] = '\0'; + nm_query_window_forward(); + if (!nm_uri_from_windowed_query(Context, buf, sizeof(buf), NotmuchQueryWindowTimebase, NotmuchQueryWindowDuration)) + mutt_message (_("Failed to create query, aborting.")); + else + { + dprint(2, (debugfile, "nm: + windowed query (%s)\n", buf)); + main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint, 0); + } + break; + case OP_MAIN_CHANGE_VFOLDER: #endif diff --git a/doc/manual.xml.head b/doc/manual.xml.head index 92a2c8553..dac7c40c0 100644 --- a/doc/manual.xml.head +++ b/doc/manual.xml.head @@ -12293,6 +12293,21 @@ virtual-mailboxes "My INBOX" "notmuch://?query=tag:inbox" <vfolder-from-query> generate virtual folder from query + + index,pager + <windowed-vfolder-from-query> + generate virtual folder from query with window applied + + + index,pager + <windowed-vfolder-forward> + generate virtual folder by moving the query's time window forward + + + index,pager + <windowed-vfolder-backward> + generate virtual folder by moving the query's time window backward + @@ -12444,6 +12459,11 @@ set vfolder_format = "%6n(%6N) %f" # as a spoolfile. set virtual_spoolfile = no +# setup time window preferences +# first setup the duration, and then the time unit of that duration +set nm_query_window_duration=2 +set nm_query_window_timebase="week" # or "hour", "day", "week", "month", "year" + # -------------------------------------------------------------------------- # FUNCTIONS - shown with an example mapping # -------------------------------------------------------------------------- @@ -12460,6 +12480,11 @@ bind index,pager \` modify-labels # generate virtual folder from query bind index,pager \eX vfolder-from-query +# generate virtual folder from query with time window +bind index,pager \\ windowed-vfolder-from-query +bind index,pager < windowed-vfolder-backward +bind index,pager > windowed-vfolder-forward + # modify labels and then hide message # bind index,pager ??? modify-labels-then-hide @@ -12557,6 +12582,7 @@ color index_tags green default Vladimir Marek Vladimir.Marek@oracle.com Víctor Manuel Jáquez Leal vjaquez@igalia.com Richard Russon rich@flatcap.org + Bernard 'Guyzmo' Pratz guyzmo+github+pub@m0g.net diff --git a/doc/muttrc.notmuch b/doc/muttrc.notmuch index d11f76839..d422390d3 100644 --- a/doc/muttrc.notmuch +++ b/doc/muttrc.notmuch @@ -44,6 +44,14 @@ set vfolder_format = "%6n(%6N) %f" # as a spoolfile. set virtual_spoolfile = no +# set the time base to apply to the time window +# valid values are: "hour", "day", "week", "month", "year" +set nm_query_window_timebase="week" + +# how large shall the window be? Any positive integer value is fine, in the +# unit of the previously defined timebase. If 0 is set, the feature is disabled. +set nm_query_window_duration=2 + # -------------------------------------------------------------------------- # FUNCTIONS - shown with an example mapping # -------------------------------------------------------------------------- @@ -60,6 +68,15 @@ bind index,pager \` modify-labels # generate virtual folder from query bind index,pager \eX vfolder-from-query +# generate a virtual folder with a time window +bind index \\ windowed-vfolder-from-query + +# move the time window forward +bind index > windowed-vfolder-forward + +# move the time window backward +bind index < windowed-vfolder-backward + # modify labels and then hide message # bind index,pager ??? modify-labels-then-hide diff --git a/doc/vimrc.notmuch b/doc/vimrc.notmuch index 5cbcfd3c4..786c517b4 100644 --- a/doc/vimrc.notmuch +++ b/doc/vimrc.notmuch @@ -6,6 +6,9 @@ syntax keyword muttrcVarBool contained skipwhite virtual_spoolfile nextgr syntax keyword muttrcVarNum contained skipwhite nm_db_limit nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr syntax keyword muttrcVarNum contained skipwhite nm_open_timeout nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax keyword muttrcVarNum contained skipwhite nm_query_window_duration nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax keyword muttrcVarNum contained skipwhite nm_query_window_timebase nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr + syntax keyword muttrcVarStr contained skipwhite nm_default_uri nextgroup=muttrcVarEqualsIdxFmt syntax keyword muttrcVarStr contained skipwhite nm_exclude_tags nextgroup=muttrcVarEqualsIdxFmt syntax keyword muttrcVarStr contained skipwhite nm_hidden_tags nextgroup=muttrcVarEqualsIdxFmt @@ -24,4 +27,7 @@ syntax match muttrcFunction contained "\" syntax match muttrcFunction contained "\" syntax match muttrcFunction contained "\" syntax match muttrcFunction contained "\" +syntax match muttrcFunction contained "\" +syntax match muttrcFunction contained "\" +syntax match muttrcFunction contained "\" diff --git a/functions.h b/functions.h index 85e229fa3..ed4ae5e36 100644 --- a/functions.h +++ b/functions.h @@ -209,6 +209,9 @@ const struct binding_t OpMain[] = { /* map: index */ #ifdef USE_NOTMUCH { "change-vfolder", OP_MAIN_CHANGE_VFOLDER, NULL }, { "vfolder-from-query", OP_MAIN_VFOLDER_FROM_QUERY, NULL }, + { "windowed-vfolder-from-query", OP_MAIN_WINDOWED_VFOLDER_FROM_QUERY, NULL }, + { "windowed-vfolder-backward", OP_MAIN_WINDOWED_VFOLDER_BACKWARD, NULL }, + { "windowed-vfolder-forward", OP_MAIN_WINDOWED_VFOLDER_FORWARD, NULL }, { "modify-labels", OP_MAIN_MODIFY_LABELS, NULL }, { "modify-labels-then-hide", OP_MAIN_MODIFY_LABELS_THEN_HIDE, NULL }, { "entire-thread", OP_MAIN_ENTIRE_THREAD, NULL }, diff --git a/globals.h b/globals.h index 1f86d7d10..55e7d871c 100644 --- a/globals.h +++ b/globals.h @@ -320,6 +320,10 @@ WHERE char *VirtFolderFormat; WHERE int NotmuchDBLimit; WHERE char *NotmuchQueryType; WHERE char *NotmuchRecordTags; +WHERE int NotmuchQueryWindowDuration; +WHERE char *NotmuchQueryWindowTimebase; +WHERE int NotmuchQueryWindowCurrentPosition; +WHERE char *NotmuchQueryWindowCurrentSearch; #endif diff --git a/init.h b/init.h index 267501468..2883bbdd8 100644 --- a/init.h +++ b/init.h @@ -2049,6 +2049,29 @@ struct option_t MuttVars[] = { ** .pp ** This variable specifies the default tags applied to messages stored to the mutt record. */ + { "nm_query_window_duration", DT_NUM, R_NONE, UL &NotmuchQueryWindowDuration, 2 }, + /* + ** .pp + ** This variable sets the time base of a windowed notmuch query. + ** Accepted values are 'minute', 'hour', 'day', 'week', 'month', 'year' + */ + { "nm_query_window_timebase", DT_STR, R_NONE, UL &NotmuchQueryWindowTimebase, UL "week" }, + /* + ** .pp + ** This variable sets the time duration of a windowed notmuch query. + ** Accepted values all non negative integers. A value of 0 disables the feature. + */ + { "nm_query_window_current_search", DT_STR, R_NONE, UL &NotmuchQueryWindowCurrentSearch, UL "" }, + /* + ** .pp + ** This variable sets the time duration of a windowed notmuch query. + ** Accepted values all non negative integers. A value of 0 disables the feature. + */ + { "nm_query_window_current_position", DT_NUM, R_NONE, UL &NotmuchQueryWindowCurrentPosition, 0 }, + /* + ** .pp + ** This variable contains the currently setup notmuch search for window based vfolder. + */ #endif { "pager", DT_PATH, R_NONE, UL &Pager, UL "builtin" }, /* diff --git a/mutt_notmuch.c b/mutt_notmuch.c index 28d2889c1..7b8cccd18 100644 --- a/mutt_notmuch.c +++ b/mutt_notmuch.c @@ -1263,6 +1263,64 @@ char *nm_uri_from_query(CONTEXT *ctx, char *buf, size_t bufsz) return buf; } +void nm_setup_windowed_query(char *buf, size_t bufsz) +{ + dprint(2, (debugfile, "nm_setup_windowed_query (%s)\n", buf)); + mutt_str_replace(&NotmuchQueryWindowCurrentSearch, buf); +} + +int nm_query_window_check_timebase(char *timebase) +{ + if ((strcmp(timebase, "hour") == 0) || + (strcmp(timebase, "day") == 0) || + (strcmp(timebase, "week") == 0) || + (strcmp(timebase, "month") == 0) || + (strcmp(timebase, "year") == 0)) + return true; + return false; +} + +char *nm_uri_from_windowed_query(CONTEXT *ctx, char *buf, size_t bufsz, char *timebase, int duration) +{ + dprint(2, (debugfile, "nm_uri_from_windowed_query (%s, %s, %d)\n", buf, timebase, duration)); + + int beg = duration * (NotmuchQueryWindowCurrentPosition + 1); + int end = duration * NotmuchQueryWindowCurrentPosition; + + if (NotmuchQueryWindowCurrentSearch == NULL) + { + nm_query_window_reset(); + return NULL; + } + + if (end == 0) + snprintf(buf, bufsz, "date:%d%s..now and %s", beg, timebase, NotmuchQueryWindowCurrentSearch); + else + snprintf(buf, bufsz, "date:%d%s..%d%s and %s", beg, timebase, end, timebase, NotmuchQueryWindowCurrentSearch); + + return nm_uri_from_query(ctx, buf, bufsz); +} + +void nm_query_window_reset() +{ + dprint(2, (debugfile, "nm_query_window_reset ()\n")); + NotmuchQueryWindowCurrentPosition = 0; +} + +void nm_query_window_backward() +{ + NotmuchQueryWindowCurrentPosition += 1; + dprint(2, (debugfile, "nm_query_window_backward (%d)\n", NotmuchQueryWindowCurrentPosition)); +} + +void nm_query_window_forward() +{ + if (NotmuchQueryWindowCurrentPosition != 0) + NotmuchQueryWindowCurrentPosition -= 1; + + dprint(2, (debugfile, "nm_query_window_forward (%d)\n", NotmuchQueryWindowCurrentPosition)); +} + /* * returns message from notmuch database */ diff --git a/mutt_notmuch.h b/mutt_notmuch.h index 8267b1fd1..c70590a11 100644 --- a/mutt_notmuch.h +++ b/mutt_notmuch.h @@ -15,6 +15,13 @@ int nm_update_filename(CONTEXT *ctx, const char *o, const char *n, HEADER *h); char *nm_uri_from_query(CONTEXT *ctx, char *buf, size_t bufsz); int nm_modify_message_tags(CONTEXT *ctx, HEADER *hdr, char *tags); +void nm_setup_windowed_query(char *buf, size_t bufsz); +char *nm_uri_from_windowed_query(CONTEXT *ctx, char *buf, size_t bufsz, char *timebase, int duration); +void nm_query_window_reset(); +void nm_query_window_backward(); +void nm_query_window_forward(); +int nm_query_window_check_timebase(char *timebase); + void nm_longrun_init(CONTEXT *cxt, int writable); void nm_longrun_done(CONTEXT *cxt);