Hi All,

I had some problems using the :buffer listing. If you have many files
(read 30+) open, the :buffer list is cluttered up with long directory
names (especially if working with files scattered over many directories)
and you loose overview. Switching to another buffer can be a real pain
especially because the completion completes on directory names. If you
have directories named like files then you're typing stuff w/o getting
to your file.

Ex.:
:buffer
/opt/vim7/src/gui.c /opt/vim7/src/structs.h
/opt/vimextra/src/vim.h /opt/vimextra/src/gui.c
configure

Although there are not so much files this is somehow cluttered. And if I
start completion for getting to vim.h it will (with list:longest)
complete on /opt/vim first. That is annoying and take too much time.

So I patched Vim (latest from svn) in order to include some emacs like
mode for :buffer listing.

:buffer
gui.c structs.h vim.h gui.c<1> configure

Directories are omitted and files having the same name get a counter. I
used Emacs for quite a long time and now since two years I'm on Vim and
it improved my work. The only thing I missed was this buffer listing.
IMHO it saves time.

Introduced a new global option called emacsbuflist (boolean) that can be
used to set this behaviour on and off.

Currently there's no help but if someone is interested in merging this
patch I'll hand doc.

Some question along the way: Why there is a did_set_string_option that
gets varp with ref to option but the did_set_option (for boolean vars)
doesn't get that? I need to update some stuff when option is set at
runtime and the only place seemed to be did_set_option but I had to do a
comparision on the option shortname (see option.c.diff).

I'm not that good at C so my code won't be the nicest one. I also don't
know if I used all vim internal functions the right way. Feedback
appreciated.

ATT: I can't compile with --with-x enabled. All other stuff works
(tested on Mac OS X). I get strange error messages about undeclared
things and I couldn't figure out what goes wrong.

Simon Pamies
Index: option.h
===================================================================
--- option.h    (revision 195)
+++ option.h    (working copy)
@@ -421,6 +421,7 @@
 #define DY_LASTLINE            0x001
 #define DY_UHEX                        0x002
 EXTERN int     p_ed;           /* 'edcompatible' */
+EXTERN int      p_embl;        /* 'emacsbuflist' */
 #ifdef FEAT_VERTSPLIT
 EXTERN char_u  *p_ead;         /* 'eadirection' */
 #endif
Index: option.c
===================================================================
--- option.c    (revision 195)
+++ option.c    (working copy)
@@ -959,6 +959,10 @@
     {"edcompatible","ed",   P_BOOL|P_VI_DEF,
                            (char_u *)&p_ed, PV_NONE,
                            {(char_u *)FALSE, (char_u *)0L}},
+    {"emacsbuflist","embl", P_BOOL|P_VI_DEF,
+                           (char_u *)&p_embl, PV_NONE,
+                           {(char_u *)FALSE, (char_u *)0L}
+                           },
     {"encoding",    "enc",  P_STRING|P_VI_DEF|P_RCLR,
 #ifdef FEAT_MBYTE
                            (char_u *)&p_enc, PV_NONE,
@@ -4752,6 +4756,13 @@
        *p = *p | P_INSECURE;
     else if (new_value)
        *p = *p & ~P_INSECURE;
+
+    /* spamsch: update shortnames if user updates option */
+    if (options[opt_idx].shortname != NULL)
+        if (STRCMP(options[opt_idx].shortname, "embl")==0) {
+            if (curbuf != NULL && curbuf->b_p_bl)
+                fill_shortnames();
+        }
 }
 
     static char_u *
Index: misc2.c
===================================================================
--- misc2.c     (revision 195)
+++ misc2.c     (working copy)
@@ -739,7 +739,7 @@
 #endif
 
 /*
- * Note: if unsinged is 16 bits we can only allocate up to 64K with alloc().
+ * Note: if unsigned is 16 bits we can only allocate up to 64K with alloc().
  * Use lalloc for larger blocks.
  */
     char_u *
Index: buffer.c
===================================================================
--- buffer.c    (revision 195)
+++ buffer.c    (working copy)
@@ -47,6 +47,7 @@
 static void    free_buffer __ARGS((buf_T *));
 static void    free_buffer_stuff __ARGS((buf_T *buf, int free_options));
 static void    clear_wininfo __ARGS((buf_T *buf));
+int             fill_shortnames __ARGS(());
 
 #ifdef UNIX
 # define dev_T dev_t
@@ -221,6 +222,11 @@
     foldUpdateAll(curwin);
 #endif
 
+    /* spamsch: Trigger setting of shortname but only
+     * option emacsbuflist is set */
+    if (p_embl)
+        fill_shortnames();
+
 #ifdef FEAT_AUTOCMD
     /* need to set w_topline, unless some autocommand already did that. */
     if (!(curwin->w_valid & VALID_TOPLINE))
@@ -449,6 +455,7 @@
 #endif
        vim_free(buf->b_ffname);
        vim_free(buf->b_sfname);
+        vim_free(buf->b_sname);
        if (buf->b_prev == NULL)
            firstbuf = buf->b_next;
        else
@@ -1569,6 +1576,8 @@
        buf->b_ffname = NULL;
        vim_free(buf->b_sfname);
        buf->b_sfname = NULL;
+        vim_free(buf->b_sname);
+        buf->b_sname = NULL;
        if (buf != curbuf)
            free_buffer(buf);
        return NULL;
@@ -1992,6 +2001,7 @@
     int                diffmode;       /* find diff-mode buffers only */
 {
     buf_T      *buf;
+    buf_T       *sbuf;
     regprog_T  *prog;
     int                match = -1;
     int                find_listed;
@@ -2059,7 +2069,22 @@
                    {
                        if (match >= 0)         /* already found a match */
                        {
-                           match = -2;
+
+                            /* spamsch: This case can happen if the 
+                             * short buffer name is used and we have
+                             * two buffers with the same name. But because
+                             * only one buffer shortname can match exactly
+                             * the given one we check the buffer names
+                             * for an exact match. */
+                            match = -2;
+
+                            if (p_embl) /* Check only if option is set */
+                                for (sbuf = firstbuf; sbuf != NULL; sbuf = 
sbuf->b_next)
+                                    if (STRCMP(sbuf->b_sname, pattern) == 0) {
+                                        match = sbuf->b_fnum;
+                                        break;
+                                    }
+
                            break;
                        }
                        match = buf->b_fnum;    /* remember first match */
@@ -2088,12 +2113,71 @@
 }
 #endif
 
+/*
+ * spamsch: Go through the buffer list and fill
+ * the field b_sname for each buffer
+ */
+    int
+fill_shortnames()
+{
+    buf_T       *buf;
+    buf_T       *sbuf;
+    char_u      *pos;
+    int         counter;
+    int         fcounter;
+
+    counter = fcounter = 0;
+    for (buf = firstbuf; buf != NULL; buf = buf->b_next) {
+
+        buf->b_sname = NULL;
+
+        if (buf->b_ffname != NULL && buf->b_p_bl) {
+            counter++;
+
+            /* We want to have the filename so we search for
+             * the last slash and get stuff behind it */
+            pos = vim_strrchr(buf->b_ffname, '/');
+
+            char_u *cpstr;
+            cpstr = (char_u *)alloc(255 * sizeof(char_u));
+            if (cpstr == NULL)
+                return FAIL;
+
+            if (pos != NULL) {
+                vim_strncpy(cpstr, pos+1, (unsigned)STRLEN(pos)-1);
+
+                for (sbuf = firstbuf; sbuf != NULL; sbuf = sbuf->b_next)
+                    if (buf != sbuf)
+                        if (sbuf->b_sname != NULL)
+                            if (STRCMP(sbuf->b_sname, cpstr) == 0) {
+                                char bnamenum[255];
+                                sprintf(bnamenum, "<%d>", ++fcounter);
+                                STRCAT(cpstr, bnamenum);
+                                break;
+                            }
+
+            } else {
+                STRCPY(cpstr, buf->b_ffname);
+            }
+
+            /* Put name into buf->b_sname */
+            buf->b_sname = vim_strsave(cpstr);
+            vim_free(cpstr);
+        }
+    }
+
+    return OK;
+
+}
+
+
 #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
 
 /*
  * Find all buffer names that match.
  * For command line expansion of ":buf" and ":sbuf".
  * Return OK if matches found, FAIL otherwise.
+ *
  */
     int
 ExpandBufnames(pat, num_file, file, options)
@@ -2206,11 +2290,18 @@
 {
     char_u     *match;
 
-    /* First try the short file name, then the long file name. */
-    match = fname_match(prog, buf->b_sfname);
-    if (match == NULL)
-       match = fname_match(prog, buf->b_ffname);
+    /* spamsch: First try b_sname as it contains the shortname */
+    if (p_embl)
+        match = fname_match(prog, buf->b_sname);
+    else match = fname_match(prog, buf->b_sfname);
 
+    if (match == NULL) {
+        /* Try the short file name, then the long file name. */
+        match = fname_match(prog, buf->b_sfname);
+        if (match == NULL)
+            match = fname_match(prog, buf->b_ffname);
+    }
+
     return match;
 }
 
@@ -2549,8 +2640,10 @@
        /* Removing the name. */
        vim_free(buf->b_ffname);
        vim_free(buf->b_sfname);
+        vim_free(buf->b_sname);
        buf->b_ffname = NULL;
        buf->b_sfname = NULL;
+        buf->b_sname = NULL;
 #ifdef UNIX
        st.st_dev = (dev_T)-1;
 #endif
@@ -2602,8 +2695,10 @@
 #endif
        vim_free(buf->b_ffname);
        vim_free(buf->b_sfname);
+        vim_free(buf->b_sname);
        buf->b_ffname = ffname;
        buf->b_sfname = sfname;
+        buf->b_sname = NULL;
     }
     buf->b_fname = buf->b_sfname;
 #ifdef UNIX
@@ -2640,8 +2735,10 @@
     {
        vim_free(buf->b_sfname);
        vim_free(buf->b_ffname);
+        vim_free(buf->b_sname);
        buf->b_ffname = vim_strsave(name);
        buf->b_sfname = NULL;
+        buf->b_sname = NULL;
        /* Allocate ffname and expand into full path.  Also resolves .lnk
         * files on Win32. */
        fname_expand(buf, &buf->b_ffname, &buf->b_sfname);
Index: structs.h
===================================================================
--- structs.h   (revision 195)
+++ structs.h   (working copy)
@@ -1149,10 +1149,24 @@
      * b_sfname is the name as the user typed it (or NULL).
      * b_fname is the same as b_sfname, unless ":cd" has been done,
      *         then it is the same as b_ffname (NULL for no name).
+     * b_sname is an unique shortname of the buffer
+     *             a) If we're having some non-filename buffer then
+     *             this is the a dummy name
+     *             b) If this is a file buffer then this contains
+     *             *ONLY* the filename. If there are two or more files
+     *             with the same name then the buffer number will be appended.
+     *
+     *             Ex.:
+     *             :buffer <TAB>
+     *             buffer.c gui.c gui.c(2) configure
+     *
+     *             This var will be filled by fill_shortname and'll be
+     *             used in ExpandBufnames.
      */
     char_u     *b_ffname;      /* full path file name */
     char_u     *b_sfname;      /* short file name */
     char_u     *b_fname;       /* current file name */
+    char_u      *b_sname;   /* the filename of the buffer w/o path */
 
 #ifdef UNIX
     int                b_dev;          /* device number (-1 if not set) */

Reply via email to