":b {bufname}" tab-completion uses whole filepath

66 views
Skip to first unread message

Enan Ajmain

unread,
Jun 14, 2024, 12:49:42 PMJun 14
to Vim Users
I use ':b' quite often. And I use a substring of the bufname to jump to
that buffer. Works quite well.

But a problem is that the substring I provide isn't only matched with
the buffer names but also the filenames. See these examples:

:ls
1 #h "example\predict.py" line 25
2 a "deeplog\deeplog.py" line 0
4 %a "example\train.py" line 37
:b deep<tab>

Then when I type ":b deep<tab>", the matches shown are:

E:\projects\log-parsing\deeplog\example\predict.py
deeplog\deeplog.py
E:\projects\log-parsing\deeplog\example\train.py

We can see that vim is matching the filepaths instead of only the buffer
names. Can I change this behavior? Preferably with vimscripting, but
I'm willing to change source code too since I use this too often.

To be clear: I want only this match to be shown:

deeplog\deeplog.py

Here's the version info:

:ver
VIM - Vi IMproved 9.1 (2024 Jan 02, compiled May 21 2024 02:04:14)
MS-Windows 64-bit console version
Included patches: 1-426
Compiled by ACER@JUDAS
Huge version without GUI. Features included (+) or not (-):
+acl +ex_extra +multi_lang -tag_any_white
+arabic +extra_search -mzscheme -tcl
+autocmd -farsi -netbeans_intg +termguicolors
+autochdir +file_in_path +num64 -terminal
+autoservername +find_in_path +packages -termresponse
-balloon_eval +float +path_extra +textobjects
+balloon_eval_term +folding -perl +textprop
-browse -footer +persistent_undo -tgetent
++builtin_terms -gettext +popupwin +timers
+byte_offset -hangul_input -postscript +title
+channel +iconv/dyn +printer -toolbar
+cindent +insert_expand +profile +user_commands
+clientserver +ipv6 -python +vartabs
+clipboard +job -python3 +vertsplit
+cmdline_compl +jumplist +quickfix +vim9script
+cmdline_hist +keymap +reltime +viminfo
+cmdline_info +lambda +rightleft +virtualedit
+comments +langmap -ruby +visual
+conceal +libcall +scrollbind +visualextra
+cryptv +linebreak +signs +vreplace
-cscope +lispindent +smartindent +vtp
+cursorbind +listcmds -sodium +wildignore
+cursorshape +localmap -sound +wildmenu
+dialog_con -lua +spell +windows
+diff +menu +startuptime +writebackup
+digraphs +mksession +statusline -xattr
-dnd +modify_fname -sun_workshop -xfontset
-ebcdic +mouse +syntax -xim
+emacs_tags -mouseshape +tag_binary -xpm_w32
+eval +multi_byte_ime/dyn -tag_old_static -xterm_save
system vimrc file: "$VIM\vimrc"
user vimrc file: "$HOME\_vimrc"
2nd user vimrc file: "$HOME\vimfiles\vimrc"
3rd user vimrc file: "$VIM\_vimrc"
user exrc file: "$HOME\_exrc"
2nd user exrc file: "$VIM\_exrc"
defaults file: "$VIMRUNTIME\defaults.vim"
Compilation: gcc -I. -Iproto -DWIN32 -DWINVER=0x0601 -D_WIN32_WINNT=0x0601 -DHAVE_PATHDEF -DFEAT_HUGE -DHAVE_STDINT_H -DFEAT_JOB_CHANNEL -DFEAT_IPV6 -DHAVE_INET_NTOP -DFEAT_MBYTE_IME -DDYNAMIC_IME -DDYNAMIC_ICONV -pipe -march=x86-64 -Wall -O3 -fomit-frame-pointer -freg-struct-return
Linking: gcc -I. -Iproto -DWIN32 -DWINVER=0x0601 -D_WIN32_WINNT=0x0601 -DHAVE_PATHDEF -DFEAT_HUGE -DHAVE_STDINT_H -DFEAT_JOB_CHANNEL -DFEAT_IPV6 -DHAVE_INET_NTOP -DFEAT_MBYTE_IME -DDYNAMIC_IME -DDYNAMIC_ICONV -pipe -march=x86-64 -Wall -O3 -fomit-frame-pointer -freg-struct-return -s -municode -o vim.exe -lkernel32 -luser32 -lgdi32 -ladvapi32 -lcomdlg32 -lcomctl32 -lnetapi32 -lversion -lws2_32 -lole32 -luuid

--
Enan

Gary Johnson

unread,
Jun 14, 2024, 3:32:51 PMJun 14
to Vim Users
On 2024-06-14, Enan Ajmain wrote:
> I use ':b' quite often. And I use a substring of the bufname to jump to
> that buffer. Works quite well.
>
> But a problem is that the substring I provide isn't only matched with
> the buffer names but also the filenames. See these examples:
>
> :ls
> 1 #h "example\predict.py" line 25
> 2 a "deeplog\deeplog.py" line 0
> 4 %a "example\train.py" line 37
> :b deep<tab>
>
> Then when I type ":b deep<tab>", the matches shown are:
>
> E:\projects\log-parsing\deeplog\example\predict.py
> deeplog\deeplog.py
> E:\projects\log-parsing\deeplog\example\train.py
>
> We can see that vim is matching the filepaths instead of only the buffer
> names. Can I change this behavior? Preferably with vimscripting, but
> I'm willing to change source code too since I use this too often.
>
> To be clear: I want only this match to be shown:
>
> deeplog\deeplog.py

The full buffer name _is_ the full file name. Vim usually tries to
show the user a shorter name such as the relative file name. If, in
your example, you were to :cd to some other directory and execute
:ls again, you would see those buffer names as full path names.

I don't know of a built-in command or option that will give you what
you want. I think you would have to write a function that would
search the buffer list for a buffer whose basename or relative path
contained the substring you supplied and execute the :b command with
that name. Just the bufname() function with the appropriate
file-pattern would do a lot of the work.

You could then create a command to call that function. The command
name would have to begin with an upper-case letter, but you can also
use :cabbrev to create an abbreviation that expands 'b' at the
beginning of the command line to your command name. That would let
you continue to use the :b command that your fingers are used to.

For <tab> to work, you'd also need to create a completion function
that followed the same matching rules as your buffer function.

Maybe not simple, but doable in vimscript.

HTH,
Gary

Christian Brabandt

unread,
Jun 14, 2024, 4:52:23 PMJun 14
to vim...@googlegroups.com

On Fr, 14 Jun 2024, Enan Ajmain wrote:

> I use ':b' quite often. And I use a substring of the bufname to jump to
> that buffer. Works quite well.
>
> But a problem is that the substring I provide isn't only matched with
> the buffer names but also the filenames. See these examples:
>
> :ls
> 1 #h "example\predict.py" line 25
> 2 a "deeplog\deeplog.py" line 0
> 4 %a "example\train.py" line 37
> :b deep<tab>
>
> Then when I type ":b deep<tab>", the matches shown are:
>
> E:\projects\log-parsing\deeplog\example\predict.py
> deeplog\deeplog.py
> E:\projects\log-parsing\deeplog\example\train.py
>
> We can see that vim is matching the filepaths instead of only the buffer
> names. Can I change this behavior? Preferably with vimscripting, but
> I'm willing to change source code too since I use this too often.
>
> To be clear: I want only this match to be shown:
>
> deeplog\deeplog.py

You could try the following mapping:

:cnoremap <expr> B getcmdtype()==#':'&&getcmdpos()==1?'b */':'B'

And then type :B which would expand to :b */ on the commandline and then
whatever you type would be anchored to the directory separator.

Thanks,
Christian
--
TAILFINS!! ... click ...

Enan Ajmain

unread,
Jun 14, 2024, 7:03:27 PMJun 14
to vim...@googlegroups.com
On Fri, 14 Jun 2024 22:52:10 +0200
Christian Brabandt <cbl...@256bit.org> wrote:
>
> You could try the following mapping:
>
> :cnoremap <expr> B getcmdtype()==#':'&&getcmdpos()==1?'b */':'B'
>
> And then type :B which would expand to :b */ on the commandline and then
> whatever you type would be anchored to the directory separator.

I think the cnoremap only maps 'B' to expand to "b */" if it's at the
start of the commandline. But what's "b */" supposed to do? I added
this mapping and then typed "deep" (so the whole commandline became "b
*/deep" and then pressed tab. It didn't do anything. No completion.

Could you explain the logic behind "anchored to the directory
separator"?

Note that I also tried "b *\" and "b *\\" since I'm in Windows.


--
Enan

Igbanam Ogbuluijah

unread,
Jun 15, 2024, 2:54:59 AMJun 15
to vim...@googlegroups.com

junegunn/fzf.vim solves this nicely. It builds on junegunn/fzf to fuzzy search on buffer names. Look into its :Buffers alongside other handy helper methods.


--
--
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

---
You received this message because you are subscribed to the Google Groups "vim_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vim_use+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/vim_use/Zmytev/J%2BUjT7XXH%40256bit.org.

Christian Brabandt

unread,
Jun 15, 2024, 9:59:31 AMJun 15
to vim...@googlegroups.com

On Fr, 14 Jun 2024, Enan Ajmain wrote:

> On Fri, 14 Jun 2024 22:52:10 +0200
> Christian Brabandt <cbl...@256bit.org> wrote:
> >
> > You could try the following mapping:
> >
> > :cnoremap <expr> B getcmdtype()==#':'&&getcmdpos()==1?'b */':'B'
> >
> > And then type :B which would expand to :b */ on the commandline and then
> > whatever you type would be anchored to the directory separator.
>
> I think the cnoremap only maps 'B' to expand to "b */" if it's at the
> start of the commandline. But what's "b */" supposed to do? I added
> this mapping and then typed "deep" (so the whole commandline became "b
> */deep" and then pressed tab. It didn't do anything. No completion.

Ah Windows, I didn't think about it. So unless you use shellslash,
you'll need to change the mapping to use a backslash instead:

:cnoremap <expr> B getcmdtype()==#':'&&getcmdpos()==1?'b *\':'B'

> Could you explain the logic behind "anchored to the directory
> separator"?

The idea is, that you want everything that you typed to be matched after
a directory separator. So instead of :b deeplog<tab> which presents you
with 3 different files, anchor the pattern to the directory separator:
\deeplog.py which Vim shall then only complete if it matches the
directory separator followed by whatever you enter.

> Note that I also tried "b *\" and "b *\\" since I'm in Windows.

Try if :b *\<pattern><tab> works for you.


Thanks,
Christian
--
Unfair animal names:

-- tsetse fly -- bullhead
-- booby -- duck-billed platypus
-- sapsucker -- Clarence
-- Gary Larson

Lifepillar

unread,
Jun 23, 2024, 9:58:44 AMJun 23
to vim...@googlegroups.com
On 2024-06-14, Enan Ajmain <3nan....@gmail.com> wrote:
> I use ':b' quite often. And I use a substring of the bufname to jump to
> that buffer. Works quite well.
>
> But a problem is that the substring I provide isn't only matched with
> the buffer names but also the filenames. See these examples:
>
> :ls
> 1 #h "example\predict.py" line 25
> 2 a "deeplog\deeplog.py" line 0
> 4 %a "example\train.py" line 37
> :b deep<tab>
>
> Then when I type ":b deep<tab>", the matches shown are:
>
> E:\projects\log-parsing\deeplog\example\predict.py
> deeplog\deeplog.py
> E:\projects\log-parsing\deeplog\example\train.py
>
> We can see that vim is matching the filepaths instead of only the buffer
> names. Can I change this behavior? Preferably with vimscripting, --

If you don't mind using a (lightweight) plugin, you can do it with my
Zeef¹ plugin. Zeef has a buffer switcher, which may or may not work for
you, but simplifying the creation of one tailored to your own specific
needs is the very purpose of the plugin. This is an example:

vim9script
import autoload 'zeef.vim'

def SwitchToBuffer(items: list<string>)
execute 'buffer' matchstr(items[0], '^\s*\zs\d\+')
enddef

zeef.Open(
execute('ls')->split("\n"),
SwitchToBuffer,
'Choose buffer',
{multi: false},
)

Hope this helps,
Life.

¹ https://github.com/lifepillar/vim-zeef



Reply all
Reply to author
Forward
0 new messages