vim-select icon indicating copy to clipboard operation
vim-select copied to clipboard

Vim fuzzy file/buffer/mru selector plugin

= vim-select: fuzzy select file/buffer/MRU/etc

NOTE: Plugin works with recent (nightly) vim having matchfuzzypos() function and prompt-buffer feature implemented.

For project files, buffers and MRU it lets you narrow down the list with fuzzy matching and select with <CR> or <Tab> if only 1 candidate is in the list.

For files it will let you go to parent directory with <BS> and to selected directory with <CR>.

Project file search uses either fd or ripgrep (with fallback to find on non-windows) tool so be sure you have one of them installed on your system. By default it uses vim current working directory as a project root.

image::https://user-images.githubusercontent.com/234774/99876845-bac99400-2c0a-11eb-87cf-e881690b20c7.gif[]

link:showcase.adoc[More animated gifs]

NOTE: Extensions are available: https://github.com/habamax/vim-select-more

== Installation

If you use package/plugin manager, consult their documentation.

For manual installation clone this repository to your ~/.vim/pack/plugins/start/ path, where plugins subdirectory is arbitrary.

NOTE: for windows users replace ~/.vim to ~/vimfiles.

== Mappings

There are no default global mappings -- create your own.

.Safe (will not create mappings if plugin was not loaded) [source,vim]

" add it to ~/.vim/after/plugin/select.vim if exists("g:loaded_select") nmap fe <Plug>(SelectFile) nmap ff <Plug>(SelectProjectFile) nmap fp <Plug>(SelectProject) nmap b <Plug>(SelectBuffer) nmap m <Plug>(SelectMRU) endif

or

.Regular [source,vim]

" add it to your vimrc nmap fe <Plug>(SelectFile) nmap ff <Plug>(SelectProjectFile) nmap fp <Plug>(SelectProject) nmap b <Plug>(SelectBuffer) nmap m <Plug>(SelectMRU)

Select window has default mappings:

  • <CR> to open/execute current item.
  • <S-CR> or <C-s> to open current item in split.
  • <C-v> to open current item in vertical split.
  • <C-t> to open current item in a tab.
  • <C-j> to create a new file out of prompt value. Only available for :Select file.
  • <ESC> to close the select window.
  • <TAB> select next item in the list, for a single item it will open/execute it.
  • <BS> open parent directory. Only for Select file.
  • <C-n> or <Down> select next item.
  • <C-p> or <Up> select previous item.
  • <PageUp> scroll up select window.
  • <PageDown> scroll down select window.

== Commands

  • :Select file from current file directory.

  • :Select file from current file directory. Or from directory passed as an argument.

  • :Select projectfile from current working directory(and sub-directories). Or from directory passed as an argument.

NOTE: External tool fd or ripgrep is required. On non-windows find would be used if none is installed.

  • :Select project from the list of projects and run :Select projectfile on it. Each project is a current working directory where :Select projectfile was run and a file was selected. The list is persisted in ~/.vim/.selectprojects or ~/.selectprojects file.

  • :Select buffer from buffer list.

  • :Select mru from v:oldfiles.

== Extending

First of all create an "extension point":

[source,vim]

let g:select_info = get(g:, "select_info", {})

And then...

=== Basic example

Let's select something from the list and echo it in vim:

[source,vim]

let g:select_info.test = {} let g:select_info.test.data = {-> ['hello', 'from', 'vim-select', 'plugin']} let g:select_info.test.sink = "echomsg '%s'"

Then with the command :Select test you can select a value from the list and see it was echoed as a vim message.

%s would be substituted with the selected value in the sink string parameter.

You can also provide a dict with action there, like:

[source,vim]

func! ShowMessage(msg) abort echom a:msg endfunc

let g:select_info.test = {} let g:select_info.test.data = {-> ['hello', 'from', 'vim-select', 'plugin']} let g:select_info.test.sink = {"action": {v -> ShowMessage(v)}}

=== Show highlight group

[source,vim]

let g:select_info.highlight = {} let g:select_info.highlight.data = {-> getcompletion('', 'highlight')} let g:select_info.highlight.sink = {"action": {v -> feedkeys(':hi '..v.."<CR>", "nt")}}

Then use :Select highlight to select and show syntax highlight group parameters.

=== Loading sessions

Imagine you have all your sessions saved in ~/.vimdata/sessions folder. I do have them there and usually create session with a helper command:

[source,vim]

command! -nargs=1 S :mksession! ~/.vimdata/sessions/

Then just a simple :S my_another_project to persist a session.

Now to narrow down and source/apply a session you can setup select plugin with:

[source,vim]

let g:select_info.session = {} let g:select_info.session.data = {-> map(glob("~/.vimdata/sessions/*", 1, 1), {_, v -> fnamemodify(v, ":t")})} let g:select_info.session.sink = "%%bd | source ~/.vimdata/sessions/%s" nnoremap fs :Select session<CR>

=== Play mp3. Yes, mp3s.

Funny thing, vim can play mp3s, so just for fun we can select a music file and play it:

[source,vim]

let g:select_info.sound = {} let g:select_info.sound.data = {"job": "rg --files --glob *.mp3"} let g:select_info.sound.sink = {"transform": {p, v -> p..v}, "action": {v -> sound_playfile(v)}}

Having this you can :Select sound ~/Music, select and play mp3 file.

A new key "transform" is to apply additional logic for a value to be passed for an action. It receives a current working directory path and a selected value. In this example the value is transformed to be a full path to a mp3 file.

=== Filetype specific example

There is b:select_info you can use in the same way as g:select_info.

For example I would like to be able to select and run https://godotengine.org/[Godot] scene and it should only be availble in https://github.com/habamax/vim-godot[gdscript] files.

Just add to ~/.vim/after/ftplugin/gdscript.vim:

[source,vim]

let b:select_info = {"godotscene": {}} let b:select_info.godotscene.data = {"job": "rg --files --glob *.tscn"} let b:select_info.godotscene.sink = {"transform": {_, v -> fnameescape(v)}, "action": "GodotRun %s"} nnoremap f :Select godotscene<CR>