int num;
} FOLDER;
+static char OldLastDir[_POSIX_PATH_MAX] = "";
static char LastDir[_POSIX_PATH_MAX] = "";
static char LastDirBackup[_POSIX_PATH_MAX] = "";
else
#endif
if (buffy)
+ {
+ menu->is_mailbox_list = 1;
snprintf (title, titlelen, _("Mailboxes [%d]"), mutt_buffy_check (0));
+ }
else
{
+ menu->is_mailbox_list = 0;
strfcpy (path, LastDir, sizeof (path));
mutt_pretty_mailbox (path, sizeof (path));
+
+ if (mutt_strncmp (LastDir, OldLastDir, mutt_strlen (LastDir)) == 0)
+ {
+ char TargetDir[_POSIX_PATH_MAX] = "";
#ifdef USE_IMAP
- if (state->imap_browse && option (OPTIMAPLSUB))
- snprintf (title, titlelen, _("Subscribed [%s], File mask: %s"),
- path, NONULL (Mask.pattern));
- else
+ if (state->imap_browse)
+ {
+ strfcpy (TargetDir, OldLastDir, sizeof (TargetDir));
+ imap_clean_path (TargetDir, sizeof (TargetDir));
+ }
+ else
#endif
+ strfcpy (TargetDir,
+ strrchr (OldLastDir, '/') + 1,
+ sizeof (TargetDir));
+
+ /* If we get here, it means that LastDir is the parent directory of
+ * OldLastDir. I.e., we're returning from a subdirectory, and we want
+ * to position the cursor on the directory we're returning from. */
+ int i;
+ for (i = 0; i < state->entrylen; i++)
+ {
+ if (mutt_strcmp (state->entry[i].name, TargetDir) == 0)
+ {
+ menu->current = i;
+ }
+ }
+ }
snprintf (title, titlelen, _("Directory [%s], File mask: %s"),
path, NONULL(Mask.pattern));
}
return ff->tagged - ot;
}
+/* Public function
+ *
+ * This function helps the browser to know which directory has
+ * been selected. It should be called anywhere a confirm hit is done
+ * to open a new directory/file which is a maildir/mbox.
+ */
+void mutt_browser_select_dir (char *f)
+{
+ strfcpy (OldLastDir, f, sizeof (OldLastDir));
+ mutt_get_parent_path (LastDir, OldLastDir, sizeof (LastDir));
+}
+
void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *numfiles)
{
char buf[_POSIX_PATH_MAX];
{
if (!folder)
getcwd (LastDir, sizeof (LastDir));
- else if (!LastDir[0])
- strfcpy (LastDir, NONULL(Maildir), sizeof (LastDir));
+ else
+ {
+ /* We use mutt_browser_select_dir to initialize the two
+ * variables (LastDir, OldLastDir) at the appropriate
+ * values.
+ */
+ if (!LastDir[0])
+ {
+ mutt_browser_select_dir (CurrentFolder);
+ }
+ else if (mutt_strcmp (CurrentFolder, OldLastDir) != 0)
+ {
+ mutt_browser_select_dir (CurrentFolder);
+ }
+ }
#ifdef USE_IMAP
if (!buffy && mx_is_imap (LastDir))
#endif
)
{
- char OldLastDir[_POSIX_PATH_MAX];
-
/* save the old directory */
strfcpy (OldLastDir, LastDir, sizeof (OldLastDir));
if (!path || !*path)
break;
strncpy (buf, path, sizeof (buf));
+
+ /* Mark the selected dir for the mutt browser */
+ mutt_browser_select_dir (buf);
}
#endif
#ifdef USE_NOTMUCH
}
else
#endif
+ /* Let's fill by default buf with the next mailbox containing
+ * unread mails
+ */
mutt_buffy (buf, sizeof (buf));
if (mutt_enter_fname (cp, buf, sizeof (buf), &menu->redraw, 1) == -1)
else
break;
}
+
+ /* Selected directory is okay, let's save it.*/
+ mutt_browser_select_dir (buf);
+
if (!buf[0])
{
mutt_window_clearline (MuttMessageWindow, 0);
</sect1>
+<sect1 id="sensible-browser">
+ <title>Sensible-Browser Patch</title>
+ <subtitle>Make the file browser behave</subtitle>
+
+ <sect2 id="sensible-browser-patch">
+ <title>Patch</title>
+
+ <para>
+ To check if Mutt supports <quote>sensible-browser</quote>, look for
+ <quote>patch-sensible-browser</quote> in the mutt version.
+ See: <xref linkend="mutt-patches"/>.
+ </para>
+
+ <itemizedlist>
+ <title>Dependencies:</title>
+ <listitem><para>mutt-1.7.0</para></listitem>
+ </itemizedlist>
+
+ <para>This patch is part of the <ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink>.</para>
+ </sect2>
+
+ <sect2 id="sensible-browser-intro">
+ <title>Introduction</title>
+
+ <para>
+ When using the file/folder browser, the selection isn't always where you would
+ expect. When you navigate to '..' (parent folder), the selection should show the
+ folder you <emphasis>used</emphasis> to be in.
+ </para>
+
+ </sect2>
+
+<!--
+ <sect2 id="sensible-browser-variables">
+ <title>Variables</title>
+ <para>None</para>
+ </sect2>
+
+ <sect2 id="sensible-browser-functions">
+ <title>Functions</title>
+ <para>None</para>
+ </sect2>
+
+ <sect2 id="sensible-browser-commands">
+ <title>Commands</title>
+ <para>None</para>
+ </sect2>
+
+ <sect2 id="sensible-browser-colors">
+ <title>Colors</title>
+ <para>None</para>
+ </sect2>
+
+ <sect2 id="sensible-browser-sort">
+ <title>Sort</title>
+ <para>None</para>
+ </sect2>
+-->
+
+ <sect2 id="sensible-browser-muttrc">
+ <title>Muttrc</title>
+ <para>None</para>
+ </sect2>
+
+ <sect2 id="sensible-browser-see-also">
+ <title>See Also</title>
+
+ <itemizedlist>
+ <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
+ </itemizedlist>
+ </sect2>
+
+ <sect2 id="sensible-browser-known-bugs">
+ <title>Known Bugs</title>
+ </sect2>
+
+ <sect2 id="sensible-browser-credits">
+ <title>Credits</title>
+ <itemizedlist>
+ <listitem><para>Pierre-Elliott Bécue <email>becue@crans.org</email></para></listitem>
+ <listitem><para>Haakon Riiser <email>haakon.riiser@fys.uio.no</email></para></listitem>
+ <listitem><para>Richard Russon <email>rich@flatcap.org</email></para></listitem>
+ </itemizedlist>
+ </sect2>
+</sect1>
+
</chapter>
<chapter id="optionalfeatures">
void imap_keepalive (void);
int imap_account_match (const ACCOUNT* a1, const ACCOUNT* a2);
+void imap_get_parent (char *output, const char *mbox, size_t olen, char delim);
+void imap_get_parent_path (char *output, const char *path, size_t olen);
+void imap_clean_path (char *path, size_t plen);
#endif
return rc;
}
+/* Public function
+ *
+ * Provided an imap mbox name and a delimiter, returns the mbox parent
+ * name.
+ *
+ * Could be static with a prototype in imap_private.h, but could be useful
+ * as a public function.
+ */
+void imap_get_parent (char *output, const char *mbox, size_t olen, char delim)
+{
+ int n;
+
+ /* If both pointers are on the same memory part
+ * strfcpy is useless
+ */
+ if (mbox != output)
+ strfcpy (output, mbox, olen);
+
+ n = mutt_strlen (output);
+
+ /* Let's go backwards untill the next delimiter
+ *
+ * If output[n] is a '/', the first n-- will allow
+ * to ignore it. If it isn't, then output looks like
+ * "/aaaaa/bbbb". There is at least one "b", so we can't skip
+ * the "/" after the 'a's.
+ *
+ * If output == '/', then n-- => n == 0, so the loop ends
+ * immediately
+ */
+ for (n--; n >= 0 && output[n] != delim ; n--);
+
+ /* We stopped before the begining. There is a trailing
+ * slash.
+ */
+ if (n > 0)
+ {
+ /* Strip the trailing delimiter. */
+ output[n] = '\0';
+ }
+ else
+ {
+ output[0] = (n == 0) ? delim : '\0';
+ }
+}
+
+/* Public function
+ * Provided an imap path, returns in output the parent directory if
+ * existent. Else returns the same path.
+ */
+void imap_get_parent_path (char *output, const char *path, size_t olen)
+{
+ IMAP_MBOX mx;
+ IMAP_DATA *idata;
+ char mbox[LONG_STRING] = "";
+
+ if (imap_parse_path (path, &mx) < 0)
+ {
+ strfcpy (output, path, olen);
+ return;
+ }
+
+ idata = imap_conn_find (&mx.account, MUTT_IMAP_CONN_NONEW);
+ if (!idata)
+ {
+ strfcpy (output, path, olen);
+ return;
+ }
+
+ /* Stores a fixed path in mbox */
+ imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox));
+
+ /* Gets the parent mbox in mbox */
+ imap_get_parent (mbox, mbox, sizeof (mbox), idata->delim);
+
+ /* Returns a fully qualified IMAP url */
+ imap_qualify_path (output, olen, &mx, mbox);
+}
+
+/* Public function
+ *
+ * Cleans an IMAP path using imap_fix_path. Does it in place.
+ */
+void imap_clean_path (char *path, size_t plen)
+{
+ IMAP_MBOX mx;
+ IMAP_DATA *idata;
+ char mbox[LONG_STRING] = "";
+
+ if (imap_parse_path (path, &mx) < 0)
+ return;
+
+ idata = imap_conn_find (&mx.account, MUTT_IMAP_CONN_NONEW);
+ if (!idata)
+ return;
+
+ /* Stores a fixed path in mbox */
+ imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox));
+
+ /* Returns a fully qualified IMAP url */
+ imap_qualify_path (path, plen, &mx, mbox);
+}
+
#ifdef USE_HCACHE
static int imap_hcache_namer (const char* path, char* dest, size_t dlen)
{
int mutt_menuLoop (MUTTMENU *menu)
{
+ static int last_position = -1;
int i = OP_NULL;
+ if (menu->max && menu->is_mailbox_list)
+ {
+ if (last_position > (menu->max - 1))
+ {
+ last_position = -1;
+ }
+ else if (last_position >= 0)
+ {
+ menu->current = last_position;
+ }
+ }
+
FOREVER
{
if (option (OPTMENUCALLER))
break;
default:
+ if (menu->is_mailbox_list)
+ last_position = menu->current;
return (i);
}
}
int offset; /* row offset within the window to start the index */
int pagelen; /* number of entries per screen */
int tagprefix;
+ int is_mailbox_list;
mutt_window_t *indexwin;
mutt_window_t *statuswin;
mutt_window_t *helpwin;
FREE (&x);
return 0;
}
+
+void mutt_get_parent_path (char *output, char *path, size_t olen)
+{
+#ifdef USE_IMAP
+ if (mx_is_imap (path))
+ imap_get_parent_path (output, path, olen);
+ else
+#endif
+ {
+ strfcpy (output, path, olen);
+ int n = mutt_strlen (output);
+
+ /* Remove everything untill the next slash */
+ for (n--; ((n >= 0) && (output[n] != '/')); n--);
+
+ if (n > 0)
+ output[n] = '\0';
+ else
+ {
+ output[0] = '/';
+ output[1] = '\0';
+ }
+ }
+}
+
void mutt_sleep (short);
int mutt_save_confirm (const char *, struct stat *);
void mutt_randbuf(void *out, size_t len);
+
+void mutt_browser_select_dir (char *f);
+void mutt_get_parent_path (char *output, char *path, size_t olen);
+
#define MUTT_RANDTAG_LEN (16)
void mutt_rand_base32(void *out, size_t len);
uint32_t mutt_rand32(void);