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"
}
case OP_MAIN_VFOLDER_FROM_QUERY:
- buf[0] = '\0';
+ buf[0] = '\0';
if (mutt_get_field ("Query: ", buf, sizeof (buf), MUTT_NM_QUERY) != 0 || !buf[0])
{
mutt_message (_("No query, aborting."));
break;
}
- if (!nm_uri_from_query(Context, buf, sizeof (buf)))
- mutt_message (_("Failed to create query, aborting."));
- else
- main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint, 0);
- break;
+ if (!nm_uri_from_query(Context, buf, sizeof (buf)))
+ mutt_message (_("Failed to create query, aborting."));
+ else
+ 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 (NotmuchQueryWindowCurrentSearch == NULL)
+ {
+ mutt_message (_("No notmuch vfolder currently loaded."));
+ break;
+ }
+ nm_query_window_backward();
+ strncpy(buf, NotmuchQueryWindowCurrentSearch, sizeof(buf));
+ if (!nm_uri_from_query(Context, buf, sizeof(buf)))
+ mutt_message (_("Failed to create query, aborting."));
+ else
+ main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint, 0);
+ break;
+
+ case OP_MAIN_WINDOWED_VFOLDER_FORWARD:
+ if (NotmuchQueryWindowDuration <= 0)
+ {
+ mutt_message (_("Windowed queries disabled."));
+ break;
+ }
+ if (NotmuchQueryWindowCurrentSearch == NULL)
+ {
+ mutt_message (_("No notmuch vfolder currently loaded."));
+ break;
+ }
+ nm_query_window_forward();
+ strncpy(buf, NotmuchQueryWindowCurrentSearch, sizeof(buf));
+ if (!nm_uri_from_query(Context, buf, sizeof(buf)))
+ 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
<entry><literal><vfolder-from-query></literal></entry>
<entry>generate virtual folder from query</entry>
</row>
+ <row>
+ <entry>index,pager</entry>
+ <entry><literal><vfolder-window-forward></literal></entry>
+ <entry>generate virtual folder by moving the query's time window forward</entry>
+ </row>
+ <row>
+ <entry>index,pager</entry>
+ <entry><literal><vfolder-window-backward></literal></entry>
+ <entry>generate virtual folder by moving the query's time window backward</entry>
+ </row>
</tbody>
</tgroup>
</table>
# as a spoolfile.</emphasis>
set virtual_spoolfile = no
+<emphasis role="comment"># setup time window preferences
+# first setup the duration, and then the time unit of that duration
+# when set to 0 (the default) the search window feature is disabled</emphasis>
+set nm_query_window_duration=2
+set nm_query_window_timebase="week" # or "hour", "day", "week", "month", "year"
+
<emphasis role="comment"># --------------------------------------------------------------------------
# FUNCTIONS - shown with an example mapping
# --------------------------------------------------------------------------
<emphasis role="comment"># generate virtual folder from query</emphasis>
bind index,pager \eX vfolder-from-query
+<emphasis role="comment"># generate virtual folder from query with time window</emphasis>
+bind index,pager < vfolder-window-backward
+bind index,pager > vfolder-window-forward
+
<emphasis role="comment"># modify labels and then hide message
# bind index,pager ??? modify-labels-then-hide
<listitem><para>Vladimir Marek <email>Vladimir.Marek@oracle.com</email></para></listitem>
<listitem><para>Víctor Manuel Jáquez Leal <email>vjaquez@igalia.com</email></para></listitem>
<listitem><para>Richard Russon <email>rich@flatcap.org</email></para></listitem>
+ <listitem><para>Bernard 'Guyzmo' Pratz <email>guyzmo+github+pub@m0g.net</email></para></listitem>
</itemizedlist>
</sect2>
</sect1>
# 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.
+# When set to 0 (the default) the search window feature is disabled</emphasis>
+set nm_query_window_duration=2
+
# --------------------------------------------------------------------------
# FUNCTIONS - shown with an example mapping
# --------------------------------------------------------------------------
# generate virtual folder from query
bind index,pager \eX vfolder-from-query
+# move the time window forward
+bind index > vfolder-window-forward
+
+# move the time window backward
+bind index < vfolder-window-backward
+
# modify labels and then hide message
# bind index,pager ??? modify-labels-then-hide
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
syntax match muttrcFunction contained "\<modify-labels\>"
syntax match muttrcFunction contained "\<sidebar-toggle-virtual\>"
syntax match muttrcFunction contained "\<vfolder-from-query\>"
+syntax match muttrcFunction contained "\<vfolder-window-forward\>"
+syntax match muttrcFunction contained "\<vfolder-window-backward\>"
#ifdef USE_NOTMUCH
{ "change-vfolder", OP_MAIN_CHANGE_VFOLDER, NULL },
{ "vfolder-from-query", OP_MAIN_VFOLDER_FROM_QUERY, NULL },
+ { "vfolder-window-backward", OP_MAIN_WINDOWED_VFOLDER_BACKWARD, NULL },
+ { "vfolder-window-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 },
WHERE int NotmuchDBLimit;
WHERE char *NotmuchQueryType;
WHERE char *NotmuchRecordTags;
+WHERE int NotmuchQueryWindowDuration;
+WHERE char *NotmuchQueryWindowTimebase;
+WHERE int NotmuchQueryWindowCurrentPosition;
+WHERE char *NotmuchQueryWindowCurrentSearch;
#endif
/*
** .pp
** This variable specifies the default tags applied to messages stored to the mutt record.
+ ** When set to 0 this variable disable the window feature.
+ */
+ { "nm_query_window_duration", DT_NUM, R_NONE, UL &NotmuchQueryWindowDuration, 0 },
+ /*
+ ** .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" },
return NM_QUERY_TYPE_MESGS;
}
+static int 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;
+}
+
+static void query_window_reset(void)
+{
+ dprint(2, (debugfile, "query_window_reset ()\n"));
+ NotmuchQueryWindowCurrentPosition = 0;
+}
+
+static int windowed_query_from_query(char *query, char *buf, size_t bufsz)
+{
+ dprint(2, (debugfile, "windowed_query_from_query (%s)\n", query));
+
+ int beg = NotmuchQueryWindowDuration * (NotmuchQueryWindowCurrentPosition + 1);
+ int end = NotmuchQueryWindowDuration * NotmuchQueryWindowCurrentPosition;
+
+ // if the duration is a non positive integer, disable the window
+ if (NotmuchQueryWindowDuration <= 0)
+ {
+ query_window_reset();
+ return 0;
+ }
+
+ // if the query has changed, reset the window position
+ if (NotmuchQueryWindowCurrentSearch == NULL ||
+ strcmp(query, NotmuchQueryWindowCurrentSearch) != 0)
+ query_window_reset();
+
+ //
+ if (!query_window_check_timebase(NotmuchQueryWindowTimebase))
+ {
+ mutt_message (_("Invalid nm_query_window_timebase value (valid values are: hour, day, week, month or year)."));
+ dprint(2, (debugfile, "Invalid nm_query_window_timebase value\n"));
+ return 0;
+ }
+
+ if (end == 0)
+ snprintf(buf, bufsz, "date:%d%s..now and %s",
+ beg, NotmuchQueryWindowTimebase, NotmuchQueryWindowCurrentSearch);
+ else
+ snprintf(buf, bufsz, "date:%d%s..%d%s and %s",
+ beg, NotmuchQueryWindowTimebase, end, NotmuchQueryWindowTimebase, NotmuchQueryWindowCurrentSearch);
+
+ return 1;
+}
+
static char *get_query_string(struct nm_ctxdata *data)
{
+ dprint(2, (debugfile, "nm: get_query_string()\n"));
+
struct uri_tag *item;
+ char buf[LONG_STRING];
if (!data)
return NULL;
if (!data->query_type)
data->query_type = string_to_query_type(NULL);
+ mutt_str_replace(&NotmuchQueryWindowCurrentSearch, data->db_query);
+
+ // if a date part is defined, do not apply windows (to avoid the risk of
+ // having a non-intersected date frame). A good improvement would be to
+ // accept if they intersect
+ if (!strstr(data->db_query, "date:") &&
+ windowed_query_from_query(data->db_query, buf, sizeof(buf)))
+ data->db_query = safe_strdup(buf);
+
dprint(2, (debugfile, "nm: query '%s'\n", data->db_query));
return data->db_query;
strfcpy(folder, old, sizeof(folder));
p = strrchr(folder, '/');
- if (p) {
+ if (p)
+ {
*p = '\0';
p++;
- } else {
- p = folder;
}
+ else
+ p = folder;
strfcpy(filename, p, sizeof(filename));
char *nm_uri_from_query(CONTEXT *ctx, char *buf, size_t bufsz)
{
+ dprint(2, (debugfile, "nm_uri_from_query (%s)\n", buf));
struct nm_ctxdata *data = get_ctxdata(ctx);
char uri[_POSIX_PATH_MAX + LONG_STRING + 32]; /* path to DB + query + URI "decoration" */
return buf;
}
+void nm_query_window_forward(void)
+{
+ if (NotmuchQueryWindowCurrentPosition != 0)
+ NotmuchQueryWindowCurrentPosition -= 1;
+
+ dprint(2, (debugfile, "nm_query_window_forward (%d)\n", NotmuchQueryWindowCurrentPosition));
+}
+
+void nm_query_window_backward(void)
+{
+ NotmuchQueryWindowCurrentPosition += 1;
+ dprint(2, (debugfile, "nm_query_window_backward (%d)\n", NotmuchQueryWindowCurrentPosition));
+}
+
int nm_modify_message_tags(CONTEXT *ctx, HEADER *hdr, char *buf)
{
struct nm_ctxdata *data = get_ctxdata(ctx);
char *nm_uri_from_query(CONTEXT *ctx, char *buf, size_t bufsz);
int nm_modify_message_tags(CONTEXT *ctx, HEADER *hdr, char *buf);
+void nm_query_window_backward(void);
+void nm_query_window_forward(void);
+
void nm_longrun_init(CONTEXT *ctx, int writable);
void nm_longrun_done(CONTEXT *ctx);