From e0cb84ca1edbfbbd50f7edaf47524439ecb146b3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pierre-Elliott=20B=C3=A9cue?= Date: Sat, 3 Sep 2016 01:52:21 +0200 Subject: [PATCH] sensible browser patch In the browser, when you go to a folder's parent, the folder you were in should be selected. This patch works for IMAP folders. --- browser.c | 66 ++++++++++++++++++++++++---- curs_main.c | 10 +++++ doc/manual.xml.head | 86 ++++++++++++++++++++++++++++++++++++ imap/imap.h | 3 ++ imap/util.c | 103 ++++++++++++++++++++++++++++++++++++++++++++ menu.c | 15 +++++++ mutt_menu.h | 1 + muttlib.c | 25 +++++++++++ protos.h | 4 ++ 9 files changed, 305 insertions(+), 8 deletions(-) diff --git a/browser.c b/browser.c index a83852de8..6d4fc51b1 100644 --- a/browser.c +++ b/browser.c @@ -76,6 +76,7 @@ typedef struct folder_t int num; } FOLDER; +static char OldLastDir[_POSIX_PATH_MAX] = ""; static char LastDir[_POSIX_PATH_MAX] = ""; static char LastDirBackup[_POSIX_PATH_MAX] = ""; @@ -894,17 +895,43 @@ static void init_menu (struct browser_state *state, MUTTMENU *menu, char *title, 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)); } @@ -927,6 +954,18 @@ static int file_tag (MUTTMENU *menu, int n, int m) 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]; @@ -1028,8 +1067,21 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num { 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)) @@ -1136,8 +1188,6 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num #endif ) { - char OldLastDir[_POSIX_PATH_MAX]; - /* save the old directory */ strfcpy (OldLastDir, LastDir, sizeof (OldLastDir)); diff --git a/curs_main.c b/curs_main.c index 3bc2fbbdf..68da7134d 100644 --- a/curs_main.c +++ b/curs_main.c @@ -1801,6 +1801,9 @@ int mutt_index_menu (void) 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 @@ -1835,6 +1838,9 @@ int mutt_index_menu (void) } 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) @@ -1847,6 +1853,10 @@ int mutt_index_menu (void) else break; } + + /* Selected directory is okay, let's save it.*/ + mutt_browser_select_dir (buf); + if (!buf[0]) { mutt_window_clearline (MuttMessageWindow, 0); diff --git a/doc/manual.xml.head b/doc/manual.xml.head index 2a2a27f5f..2af87451e 100644 --- a/doc/manual.xml.head +++ b/doc/manual.xml.head @@ -8289,6 +8289,92 @@ for example, in a global .muttrc. + + Sensible-Browser Patch + Make the file browser behave + + + Patch + + + To check if Mutt supports sensible-browser, look for + patch-sensible-browser in the mutt version. + See: . + + + + Dependencies: + mutt-1.7.0 + + + This patch is part of the NeoMutt Project. + + + + Introduction + + + 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 used to be in. + + + + + + + + Muttrc + None + + + + See Also + + + NeoMutt Project + + + + + Known Bugs + + + + Credits + + Pierre-Elliott Bécue becue@crans.org + Haakon Riiser haakon.riiser@fys.uio.no + Richard Russon rich@flatcap.org + + + + diff --git a/imap/imap.h b/imap/imap.h index 94506ea98..584982d5f 100644 --- a/imap/imap.h +++ b/imap/imap.h @@ -70,5 +70,8 @@ int imap_wait_keepalive (pid_t pid); 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 diff --git a/imap/util.c b/imap/util.c index 924d57364..8c77c88a9 100644 --- a/imap/util.c +++ b/imap/util.c @@ -72,6 +72,109 @@ int imap_expand_path (char* path, size_t len) 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) { diff --git a/menu.c b/menu.c index 252760c4b..d56c5a45d 100644 --- a/menu.c +++ b/menu.c @@ -938,8 +938,21 @@ int menu_redraw (MUTTMENU *menu) 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)) @@ -1163,6 +1176,8 @@ int mutt_menuLoop (MUTTMENU *menu) break; default: + if (menu->is_mailbox_list) + last_position = menu->current; return (i); } } diff --git a/mutt_menu.h b/mutt_menu.h index d5c97d017..be4165d15 100644 --- a/mutt_menu.h +++ b/mutt_menu.h @@ -53,6 +53,7 @@ typedef struct menu_t 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; diff --git a/muttlib.c b/muttlib.c index 067be7765..13af56b91 100644 --- a/muttlib.c +++ b/muttlib.c @@ -2168,3 +2168,28 @@ int mutt_set_xdg_path(const XDGType type, char *buf, size_t bufsize) 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'; + } + } +} + diff --git a/protos.h b/protos.h index ec9c0a7f2..5d02bd087 100644 --- a/protos.h +++ b/protos.h @@ -404,6 +404,10 @@ void mutt_set_header_color(CONTEXT *, HEADER *); 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); -- 2.50.0