I came up with a solution which I think does what you want.
I know that you asked only for hints, so I'll write hints I would have given and then the final function. You'll be free to read it or not.
So here are my tips:
Creating a function
You said you were really new to vimscript, so here is a short reminder on functions.
They begins with function! NameOfTheFunc()
(note the first capital letter on the name and the parentheses) and end with endfunction
. You can put them in your .vimrc
file to let vim source them at each start.
Getting the output of a function
If you want to get the output of a function to manipulate it, you can put it in a register thanks to the redir
function. A use case using :ls
(hey that's also a hint ;-) ) would be the following:
redir @n exec 'ls' redir END
This would put the result of :ls
in the register @n
.
Doing substitutions on the content of a register
I think you probably know the :s
command and maybe the substitute()
function. It is possible to use the latter to do substitution on the text of a register:
substitute(@n, {pattern}, {sub}, {flag})
Will apply the substitution on the register @n
.
What about submatches?
I don't know how familiar you are with the substitute
command so I'll also remind you that it is possible to create submatches. I think :h :substitute
could interest you on this topic (I'll maybe edit this answer to put a link to a more relevant documentation). Basically it allows us to capture only a part of the pattern you're matching and reuse it.
The important point is that to use submatches with the substitute()
function your call should look like this:
substitute(@n, {pattern}, '\=submatch(X)', {tags})
Where X
is the number of the submatch you want to use. \=
allows us to evaluate the content of the {sub}
part instead of just using it literally.
And finally some regex
I will not make a complete explanation of regex here because it would be really long and I'm really not qualified to do that :-) This topic should be a start: :h regexp
.
Also the function substitute()
use magic parameter by default. So see :h magic
.
Creating a command to feel "pro"
As we will create a function (let's call it ListBuffers()
) that we will
potentially call (very) often, we could create a custom ex command which is way faster to call than a function. To do so, we simply have to add the following line:
command! LS call ListBuffers()
With this line, typing :LS
will be equivalent to typing call ListBuffers()
.
For the next step, I'll shamelessly stole a hint that I got from this VanLaser answer, many thanks to him. OP will probably not want to follow this step since you stated that you don't want to override :ls
.
Our command :LS
fills the same purpose as :ls
, it is possible thanks to the alterCmd
plugin to override the original :ls
to use it instead our command.
With alterCmd
installed, we can use the following line:
:AlterCommand ls LS
To replace the original :ls
command with our custom one. This way, typing :ls
will show the buffer list with the shortened names.
And then we have a function
Finally, with those different elements, I came up with a function which:
- Gets the output of
:ls
in a register
- Substitutes the full path to simply the name of the file
- Put this result in a variable
- Output this variable
function! ListBuffers()
redir @n
silent exec 'ls'
redir END
let list = substitute(@n, '"(\f*\)*(\f*)"' , '\=submatch(2)', "g")
echo list
endfunction
Note the silent
on line 3 which ensures that we execute ls
but don't output its result on the screen so you have the list only once.
Note also the regex which can probably be improved. It creates 2 submatches. The first one contains \f*\\
which is as many file-name characters as possible followed by a literal \
and repeated as many time as possible. The second submatch only contains file-name characters and is the one used to replace the whole path.
Note: I created this regex on Windows because I don't have access to a Linux box right now, you might need to replace the literal \
by a literal /
to make it work on Linux.
Here is the result of :ls
on my machine:

And the result of my ListBuffers()
function:

PS: Sorry for the long answer, I hope it helped ;-)
EDIT Carpetsmoker suggested using a variable instead of a register and I think he is particularly right. This way, using the function will not clobber the state of the register. So a better version of the function is:
function! ListBuffers()
redir => ls_output
silent exec 'ls'
redir END
let list = substitute(ls_output, '"(\f*\)*(\f*)"' , '\=submatch(2)', "g")
echo list
endfunction
An alternative was to use getRegister()
to save the state of @n
and setRegister()
to give it its previous state, but that's less effective than using a variable.
:b
can take partial filenames. Then use<tab>
completion to deal with multiple matches. No more worrying about:ls
.:Ex
, see:help netrw
.:Vex
and:Sex
frequently as well. They serve a different purpose however: files are not in the same directory and can be pretty spread out.:b <phrase> <tab> <Enter>
approach, that works great! If you know the name of the buffer, type a unique part of the buffer name (e.g.):b 2b <tab>
or:b b. <tab>
to expand:b /mnt/Vancouver/Programming/data/file2b.txt
. Then hit the<Enter>
key to open that buffer. It's a clean, "native" approach! :-)