]> granicus.if.org Git - vim/commitdiff
patch 8.1.2225: the "last used" info of a buffer is under used v8.1.2225
authorBram Moolenaar <Bram@vim.org>
Sun, 27 Oct 2019 04:12:45 +0000 (05:12 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 27 Oct 2019 04:12:45 +0000 (05:12 +0100)
Problem:    The "last used" info of a buffer is under used.
Solution:   Add "lastused" to getbufinfo(). List buffers sorted by last-used
            field. (Andi Massimino, closes #4722)

18 files changed:
runtime/doc/eval.txt
runtime/doc/options.txt
runtime/doc/windows.txt
src/buffer.c
src/evalbuffer.c
src/ex_getln.c
src/misc1.c
src/option.c
src/option.h
src/proto/misc1.pro
src/proto/viminfo.pro
src/testdir/test_bufwintabinfo.vim
src/testdir/test_cmdline.vim
src/testdir/test_excmd.vim
src/undo.c
src/version.c
src/vim.h
src/viminfo.c

index a167d5f56303bc3a0213b5b72eef4dbcea84e497..f50c8c5b879f545bafe67af8a635981e7addd800 100644 (file)
@@ -4778,6 +4778,10 @@ getbufinfo([{dict}])
                        changed         TRUE if the buffer is modified.
                        changedtick     number of changes made to the buffer.
                        hidden          TRUE if the buffer is hidden.
+                       lastused        timestamp in seconds, like
+                                       |localtime()|, when the buffer was
+                                       last used.
+                                       {only with the |+viminfo| feature}
                        listed          TRUE if the buffer is listed.
                        lnum            current line number in buffer.
                        loaded          TRUE if the buffer is loaded.
index 029a0727f4c24a3d8b0955fec4597a94ca59118d..6e4ff1d6f51d36113f647a94df16733872ad5156 100644 (file)
@@ -8689,6 +8689,8 @@ A jump table for the options with a short description can be found at |Q_op|.
                        complete first match.
        "list:longest"  When more than one match, list all matches and
                        complete till longest common string.
+       "list:lastused" When more than one buffer matches, sort buffers
+                       by time last used (other than the current buffer).
        When there is only a single match, it is fully completed in all cases.
 
        Examples: >
index 0c37cf53993f3aa9a590fbe1f5d675f6a6c990c5..813de1b664579d9365bc35ec36012f9effb4ebaf 100644 (file)
@@ -1090,6 +1090,7 @@ list of buffers. |unlisted-buffer|
                     R   terminal buffers with a running job
                     F   terminal buffers with a finished job
                     ?   terminal buffers without a job: `:terminal NONE`
+                    t   show time last used and sort buffers
                Combining flags means they are "and"ed together, e.g.:
                     h+   hidden buffers which are modified
                     a+   active buffers which are modified
index 86f6ffcedb8f1a8e9260b25d03b365385fb99035..15fbc173e8e82febc278c1b64ae2f2e6f6660cf1 100644 (file)
@@ -2601,6 +2601,13 @@ buflist_findpat(
     return match;
 }
 
+#ifdef FEAT_VIMINFO
+typedef struct {
+    buf_T   *buf;
+    char_u  *match;
+} bufmatch_T;
+#endif
+
 /*
  * Find all buffer names that match.
  * For command line expansion of ":buf" and ":sbuf".
@@ -2619,6 +2626,9 @@ ExpandBufnames(
     char_u     *p;
     int                attempt;
     char_u     *patc;
+#ifdef FEAT_VIMINFO
+    bufmatch_T *matches = NULL;
+#endif
 
     *num_file = 0;                 /* return values in case of FAIL */
     *file = NULL;
@@ -2675,7 +2685,16 @@ ExpandBufnames(
                            p = home_replace_save(buf, p);
                        else
                            p = vim_strsave(p);
-                       (*file)[count++] = p;
+#ifdef FEAT_VIMINFO
+                       if (matches != NULL)
+                       {
+                           matches[count].buf = buf;
+                           matches[count].match = p;
+                           count++;
+                       }
+                       else
+#endif
+                           (*file)[count++] = p;
                    }
                }
            }
@@ -2691,6 +2710,10 @@ ExpandBufnames(
                        vim_free(patc);
                    return FAIL;
                }
+#ifdef FEAT_VIMINFO
+               if (options & WILD_BUFLASTUSED)
+                   matches = ALLOC_MULT(bufmatch_T, count);
+#endif
            }
        }
        vim_regfree(regmatch.regprog);
@@ -2701,6 +2724,28 @@ ExpandBufnames(
     if (patc != pat)
        vim_free(patc);
 
+#ifdef FEAT_VIMINFO
+    if (matches != NULL)
+    {
+       int i;
+       if (count > 1)
+           qsort(matches, count, sizeof(bufmatch_T), buf_compare);
+       // if the current buffer is first in the list, place it at the end
+       if (matches[0].buf == curbuf)
+       {
+           for (i = 1; i < count; i++)
+               (*file)[i-1] = matches[i].match;
+           (*file)[count-1] = matches[0].match;
+       }
+       else
+       {
+           for (i = 0; i < count; i++)
+               (*file)[i] = matches[i].match;
+       }
+       vim_free(matches);
+    }
+#endif
+
     *num_file = count;
     return (count == 0 ? FAIL : OK);
 }
@@ -3016,7 +3061,7 @@ buflist_findlnum(buf_T *buf)
     void
 buflist_list(exarg_T *eap)
 {
-    buf_T      *buf;
+    buf_T      *buf = firstbuf;
     int                len;
     int                i;
     int                ro_char;
@@ -3026,7 +3071,32 @@ buflist_list(exarg_T *eap)
     int                job_none_open;
 #endif
 
+#ifdef FEAT_VIMINFO
+    garray_T   buflist;
+    buf_T      **buflist_data = NULL, **p;
+
+    if (vim_strchr(eap->arg, 't'))
+    {
+       ga_init2(&buflist, sizeof(buf_T *), 50);
+       for (buf = firstbuf; buf != NULL; buf = buf->b_next)
+       {
+           if (ga_grow(&buflist, 1) == OK)
+               ((buf_T **)buflist.ga_data)[buflist.ga_len++] = buf;
+       }
+
+       qsort(buflist.ga_data, (size_t)buflist.ga_len,
+               sizeof(buf_T *), buf_compare);
+
+       p = buflist_data = (buf_T **)buflist.ga_data;
+       buf = *p;
+    }
+
+    for (; buf != NULL && !got_int; buf = buflist_data
+           ? (++p < buflist_data + buflist.ga_len ? *p : NULL)
+           : buf->b_next)
+#else
     for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next)
+#endif
     {
 #ifdef FEAT_TERMINAL
        job_running = term_job_running(buf->b_term);
@@ -3100,13 +3170,23 @@ buflist_list(exarg_T *eap)
        do
            IObuff[len++] = ' ';
        while (--i > 0 && len < IOSIZE - 18);
-       vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len),
-               _("line %ld"), buf == curbuf ? curwin->w_cursor.lnum
+#ifdef FEAT_VIMINFO
+       if (vim_strchr(eap->arg, 't') && buf->b_last_used)
+           add_time(IObuff + len, (size_t)(IOSIZE - len), buf->b_last_used);
+       else
+#endif
+           vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len),
+                   _("line %ld"), buf == curbuf ? curwin->w_cursor.lnum
                                               : (long)buflist_findlnum(buf));
        msg_outtrans(IObuff);
        out_flush();        /* output one line at a time */
        ui_breakcheck();
     }
+
+#ifdef FEAT_VIMINFO
+    if (buflist_data)
+       ga_clear(&buflist);
+#endif
 }
 
 /*
index 35c9ed2459a084e10b9d2a74acf97aa5b829bee7..a82b89727e0c1104fc66cdb7c631fc08f0c28cf1 100644 (file)
@@ -595,6 +595,10 @@ get_buffer_info(buf_T *buf)
     }
 #endif
 
+#ifdef FEAT_VIMINFO
+    dict_add_number(dict, "lastused", buf->b_last_used);
+#endif
+
     return dict;
 }
 
index 9c98f99babb5b0a5e411e699fe7599a096c3b97c..5cc1c3489752e4bd0283ef51bf6e5d43f9346905 100644 (file)
@@ -1407,6 +1407,9 @@ getcmdline_int(
         */
        if ((c == p_wc && !gotesc && KeyTyped) || c == p_wcm)
        {
+           int options = WILD_NO_BEEP;
+           if (wim_flags[wim_index] & WIM_BUFLASTUSED)
+               options |= WILD_BUFLASTUSED;
            if (xpc.xp_numfiles > 0)   /* typed p_wc at least twice */
            {
                /* if 'wildmode' contains "list" may still need to list */
@@ -1419,10 +1422,10 @@ getcmdline_int(
                    did_wild_list = TRUE;
                }
                if (wim_flags[wim_index] & WIM_LONGEST)
-                   res = nextwild(&xpc, WILD_LONGEST, WILD_NO_BEEP,
+                   res = nextwild(&xpc, WILD_LONGEST, options,
                                                               firstc != '@');
                else if (wim_flags[wim_index] & WIM_FULL)
-                   res = nextwild(&xpc, WILD_NEXT, WILD_NO_BEEP,
+                   res = nextwild(&xpc, WILD_NEXT, options,
                                                               firstc != '@');
                else
                    res = OK;       /* don't insert 'wildchar' now */
@@ -1434,10 +1437,10 @@ getcmdline_int(
                /* if 'wildmode' first contains "longest", get longest
                 * common part */
                if (wim_flags[0] & WIM_LONGEST)
-                   res = nextwild(&xpc, WILD_LONGEST, WILD_NO_BEEP,
+                   res = nextwild(&xpc, WILD_LONGEST, options,
                                                               firstc != '@');
                else
-                   res = nextwild(&xpc, WILD_EXPAND_KEEP, WILD_NO_BEEP,
+                   res = nextwild(&xpc, WILD_EXPAND_KEEP, options,
                                                               firstc != '@');
 
                /* if interrupted while completing, behave like it failed */
@@ -1488,10 +1491,10 @@ getcmdline_int(
                        redrawcmd();
                        did_wild_list = TRUE;
                        if (wim_flags[wim_index] & WIM_LONGEST)
-                           nextwild(&xpc, WILD_LONGEST, WILD_NO_BEEP,
+                           nextwild(&xpc, WILD_LONGEST, options,
                                                               firstc != '@');
                        else if (wim_flags[wim_index] & WIM_FULL)
-                           nextwild(&xpc, WILD_NEXT, WILD_NO_BEEP,
+                           nextwild(&xpc, WILD_NEXT, options,
                                                               firstc != '@');
                    }
                    else
index 0e182555ac651e18674e9d6365fb8c78df10a608..74c8eaa66fa622621c4f25ac673ec9e905007d69 100644 (file)
@@ -2576,3 +2576,34 @@ path_with_url(char_u *fname)
        ;
     return path_is_url(p);
 }
+
+/*
+ * Put timestamp "tt" in "buf[buflen]" in a nice format.
+ */
+    void
+add_time(char_u *buf, size_t buflen, time_t tt)
+{
+#ifdef HAVE_STRFTIME
+    struct tm  tmval;
+    struct tm  *curtime;
+
+    if (vim_time() - tt >= 100)
+    {
+       curtime = vim_localtime(&tt, &tmval);
+       if (vim_time() - tt < (60L * 60L * 12L))
+           /* within 12 hours */
+           (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime);
+       else
+           /* longer ago */
+           (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", curtime);
+    }
+    else
+#endif
+    {
+       long seconds = (long)(vim_time() - tt);
+
+       vim_snprintf((char *)buf, buflen,
+               NGETTEXT("%ld second ago", "%ld seconds ago", seconds),
+               seconds);
+    }
+}
index 3314a3c4b74b861374fde67d8be3423c5db2159c..1140a01ac208bc52b260aa3675c92b90e5642a99 100644 (file)
@@ -6987,6 +6987,8 @@ check_opt_wim(void)
            new_wim_flags[idx] |= WIM_FULL;
        else if (i == 4 && STRNCMP(p, "list", 4) == 0)
            new_wim_flags[idx] |= WIM_LIST;
+       else if (i == 8 && STRNCMP(p, "lastused", 8) == 0)
+           new_wim_flags[idx] |= WIM_BUFLASTUSED;
        else
            return FAIL;
        p += i;
index 254ca6a2820b5ee2d84ec352f4d1f6cd4046fb9f..3ee9979133f47d7d4754d3d326a688e454b7babd 100644 (file)
 #define WIM_FULL       0x01
 #define WIM_LONGEST    0x02
 #define WIM_LIST       0x04
+#define WIM_BUFLASTUSED        0x08
 
 // arguments for can_bs()
 #define BS_INDENT      'i'     // "Indent"
index 1a06d7ed7f83dc69c01c715941a78c18de07054c..2f7bd03885a467e7c03b3a2048e90b57fc00b4eb 100644 (file)
@@ -46,4 +46,5 @@ int goto_im(void);
 char_u *get_isolated_shell_name(void);
 int path_is_url(char_u *p);
 int path_with_url(char_u *fname);
+void add_time(char_u *buf, size_t buflen, time_t tt);
 /* vim: set ft=c : */
index a1f03373d762fed253b3c2c69bdc1da0deb42f90..b1f97f6ede881a4854b2c6a03a46d4c383573d92 100644 (file)
@@ -3,5 +3,6 @@ int get_viminfo_parameter(int type);
 void check_marks_read(void);
 int read_viminfo(char_u *file, int flags);
 void write_viminfo(char_u *file, int forceit);
+int buf_compare(const void *s1, const void *s2);
 void ex_viminfo(exarg_T *eap);
 /* vim: set ft=c : */
index ee22ebd455e6b58fc82df1a0850dfd83dd032039..b4b8a109bd4ee53c9786a4731d695db672873a60 100644 (file)
@@ -139,3 +139,15 @@ function Test_get_win_options()
     set foldlevel=0
   endif
 endfunc
+
+function Test_getbufinfo_lastused()
+  call test_settime(1234567)
+  edit Xtestfile1
+  enew
+  call test_settime(7654321)
+  edit Xtestfile2
+  enew
+  call assert_equal(getbufinfo('Xtestfile1')[0].lastused, 1234567)
+  call assert_equal(getbufinfo('Xtestfile2')[0].lastused, 7654321)
+  call test_settime(0)
+endfunc
index 55f35e7dd6a03e41289ea554fd387daae469c3af..57dff4167316b3b4bf6a61562e47b57c0ff74090 100644 (file)
@@ -767,3 +767,48 @@ func Test_cmdwin_bug()
   endtry
   bw!
 endfunc
+
+func Test_buffers_lastused()
+  " check that buffers are sorted by time when wildmode has lastused
+  call test_settime(1550020000)          " middle
+  edit bufa
+  enew
+  call test_settime(1550030000)          " newest
+  edit bufb
+  enew
+  call test_settime(1550010000)          " oldest
+  edit bufc
+  enew
+  call test_settime(0)
+  enew
+
+  call assert_equal(['bufa', 'bufb', 'bufc'],
+       \ getcompletion('', 'buffer'))
+
+  let save_wildmode = &wildmode
+  set wildmode=full:lastused
+
+  let cap = "\<c-r>=execute('let X=getcmdline()')\<cr>"
+  call feedkeys(":b \<tab>" .. cap .. "\<esc>", 'xt')
+  call assert_equal('b bufb', X)
+  call feedkeys(":b \<tab>\<tab>" .. cap .. "\<esc>", 'xt')
+  call assert_equal('b bufa', X)
+  call feedkeys(":b \<tab>\<tab>\<tab>" .. cap .. "\<esc>", 'xt')
+  call assert_equal('b bufc', X)
+  enew
+
+  edit other
+  call feedkeys(":b \<tab>" .. cap .. "\<esc>", 'xt')
+  call assert_equal('b bufb', X)
+  call feedkeys(":b \<tab>\<tab>" .. cap .. "\<esc>", 'xt')
+  call assert_equal('b bufa', X)
+  call feedkeys(":b \<tab>\<tab>\<tab>" .. cap .. "\<esc>", 'xt')
+  call assert_equal('b bufc', X)
+  enew
+
+  let &wildmode = save_wildmode
+
+  bwipeout bufa
+  bwipeout bufb
+  bwipeout bufc
+endfunc
index 509d78dfbafcf9934917495f5843b0d6f816a2ce..992fc3de07b4f00258d6590648e481c0ed0717e8 100644 (file)
@@ -19,3 +19,28 @@ func Test_range_error()
   normal vv
   call assert_fails(":'<,'>echo 1", 'E481:')
 endfunc
+
+func Test_buffers_lastused()
+  call test_settime(localtime() - 2000) " middle
+  edit bufa
+  enew
+  call test_settime(localtime() - 10)   " newest
+  edit bufb
+  enew
+  call test_settime(1550010000)                " oldest
+  edit bufc
+  enew
+  call test_settime(0)
+  enew
+
+  let ls = split(execute('buffers t', 'silent!'), '\n')
+  let bufs = ls->map({i,v->split(v, '"\s*')[1:2]})
+  call assert_equal(['bufb', 'bufa', 'bufc'], bufs[1:]->map({i,v->v[0]}))
+  call assert_match('1[0-3] seconds ago', bufs[1][1])
+  call assert_match('\d\d:\d\d:\d\d', bufs[2][1])
+  call assert_match('2019/02/1\d \d\d:\d\d:00', bufs[3][1])
+
+  bwipeout bufa
+  bwipeout bufb
+  bwipeout bufc
+endfunc
index 2736f2a33dcdf79caf3b824b593ea9f473149127..64fb2050c3f688f2001698301dfc62dc7aedeb03 100644 (file)
@@ -106,7 +106,6 @@ static void u_getbot(void);
 static void u_doit(int count);
 static void u_undoredo(int undo);
 static void u_undo_end(int did_undo, int absolute);
-static void u_add_time(char_u *buf, size_t buflen, time_t tt);
 static void u_freeheader(buf_T *buf, u_header_T *uhp, u_header_T **uhpp);
 static void u_freebranch(buf_T *buf, u_header_T *uhp, u_header_T **uhpp);
 static void u_freeentries(buf_T *buf, u_header_T *uhp, u_header_T **uhpp);
@@ -2973,7 +2972,7 @@ u_undo_end(
     if (uhp == NULL)
        *msgbuf = NUL;
     else
-       u_add_time(msgbuf, sizeof(msgbuf), uhp->uh_time);
+       add_time(msgbuf, sizeof(msgbuf), uhp->uh_time);
 
 #ifdef FEAT_CONCEAL
     {
@@ -3050,7 +3049,7 @@ ex_undolist(exarg_T *eap UNUSED)
                break;
            vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7d  ",
                                                        uhp->uh_seq, changes);
-           u_add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff),
+           add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff),
                                                                uhp->uh_time);
            if (uhp->uh_save_nr > 0)
            {
@@ -3124,37 +3123,6 @@ ex_undolist(exarg_T *eap UNUSED)
     }
 }
 
-/*
- * Put the timestamp of an undo header in "buf[buflen]" in a nice format.
- */
-    static void
-u_add_time(char_u *buf, size_t buflen, time_t tt)
-{
-#ifdef HAVE_STRFTIME
-    struct tm  tmval;
-    struct tm  *curtime;
-
-    if (vim_time() - tt >= 100)
-    {
-       curtime = vim_localtime(&tt, &tmval);
-       if (vim_time() - tt < (60L * 60L * 12L))
-           /* within 12 hours */
-           (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime);
-       else
-           /* longer ago */
-           (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", curtime);
-    }
-    else
-#endif
-    {
-       long seconds = (long)(vim_time() - tt);
-
-       vim_snprintf((char *)buf, buflen,
-               NGETTEXT("%ld second ago", "%ld seconds ago", seconds),
-               seconds);
-    }
-}
-
 /*
  * ":undojoin": continue adding to the last entry list
  */
index 62a48880d72afe527e903bdc9697c57905a05c33..3f36958a692582b2e8fd151d627cf1ab74d40595 100644 (file)
@@ -741,6 +741,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2225,
 /**/
     2224,
 /**/
index 917dbfa7245c20231d47315b0fc687dafab00e7c..230f5b3f8d6fe2712f65ec07e5e2ed106cb19dbf 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -811,6 +811,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
 #define WILD_ALLLINKS              0x200
 #define WILD_IGNORE_COMPLETESLASH   0x400
 #define WILD_NOERROR               0x800  // sets EW_NOERROR
+#define WILD_BUFLASTUSED           0x1000
 
 // Flags for expand_wildcards()
 #define EW_DIR         0x01    // include directory names
index b16282856b5eecb4639dd69606679c0b714eec00..a49bb01daf253d7cdf5a8eedbb02ec9594c325bb 100644 (file)
@@ -2152,7 +2152,7 @@ write_viminfo_filemarks(FILE *fp)
 /*
  * Compare functions for qsort() below, that compares b_last_used.
  */
-    static int
+    int
 buf_compare(const void *s1, const void *s2)
 {
     buf_T *buf1 = *(buf_T **)s1;