Skip to content

girishji/vimsuggest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

VimSuggest: Supercharge Your Vim Command-Line

The ultimate auto-completion plugin for Vim command-line.

🚀 Enhance Vim Workflow

  • Command Completion: Never struggle to remember complex commands again.
  • Search Suggestions: Access relevant search terms with fewer keystrokes, enhancing your navigation.

🌟 Additional Features

VimSuggest goes beyond basic auto-completion, offering a suite of advanced features by leveraging Vim's native custom completion mechanism (:h :command-completion-custom). These features feel like a natural extension of the editor, but they can be easily disabled if desired.

  • Asynchronous Fuzzy File Search (:VSFind): Effortlessly locate files across your entire project with minimal keystrokes.
  • Real-Time Live Grep (:VSGrep): Instantly find text across your entire codebase using glob or regex patterns.
  • Fuzzy Search: Quickly locate buffers (:VSBuffer) and search various Vim artifacts.
  • In-Buffer Search (:VSGlobal): Leverage Vim's powerful :global command for lightning-fast buffer searches.
  • Include File Search (:VSInclSearch): Seamlessly search across included files using Vim's :ilist command.
  • Live File Search (:VSFindL): Asynchronously search for files using glob or regex patterns.
  • Custom Shell Command Execution (:VSExec): Run and interact with shell commands directly within Vim.

Auto-completion can also be disabled by default and only triggered when the <Tab> key is pressed, which more closely aligns with Vim's default behavior.


Demo


Requirements

  • Vim version 9.1 or higher

Installation

Install VimSuggest via vim-plug or Vim's built-in package manager.

Show installation instructions

Using vim-plug

Add the following to your .vimrc:

call plug#begin()
Plug 'girishji/vimsuggest'
call plug#end()

Using Vim's built-in package manager

mkdir -p $HOME/.vim/pack/downloads/opt
cd $HOME/.vim/pack/downloads/opt
git clone https://github.com/girishji/vimsuggest.git

Then add this line to your .vimrc file:

packadd vimsuggest

Configuration Guide

VimSuggest offers extensive customization options for both command completion and search completion.

Command Completion Configuration

let s:vim_suggest = {}
let s:vim_suggest.cmd = {
    \ 'enable': v:true,
    \ 'pum': v:true,
    \ 'fuzzy': v:false,
    \ 'exclude': [],
    \ 'onspace': [],
    \ 'alwayson': v:true,
    \ 'popupattrs': {},
    \ 'wildignore': v:true,
    \ 'addons': v:true,
    \ 'ctrl_np': v:false,
\ }
Variable Name Default Value Comment
enable v:true Enable/disable command completion
pum v:true Use stacked popup menu (v:false for flat)
fuzzy v:false Enable fuzzy completion matching
exclude [] Regex patterns to exclude from completion
onspace [] Commands to complete after space (e.g., 'buffer')
alwayson v:true Auto-open popup (v:false to open with )
popupattrs {} Arguments passed to popup_create() (:h popup_create-arguments)
wildignore v:true Respect 'wildignore' during file completion
addons v:true Enable addons (:VSxxx commands)
ctrl_np v:false <C-n/p> selects menu when 'true'; otherwise, recalls history

Search Completion Configuration

let s:vim_suggest.search = {
    \ 'enable': v:true,
    \ 'pum': v:true,
    \ 'fuzzy': v:false,
    \ 'alwayson': v:true,
    \ 'popupattrs': {
    \   'maxheight': 12
    \ },
    \ 'range': 100,
    \ 'timeout': 200,
    \ 'async': v:true,
    \ 'async_timeout': 3000,
    \ 'async_minlines': 1000,
    \ 'highlight': v:true,
    \ 'ctrl_np': v:false,
\ }
Variable Name Default Value Comment
enable v:true Enable/disable search completion
pum v:true Use flat menu (v:true for stacked)
fuzzy v:false Enable fuzzy completion
alwayson v:true Auto-open popup (v:false to open with )
popupattrs {'maxheight': 12} Arguments passed to popup_create() (:h popup_create-arguments)
range 100 Lines to search in each batch
timeout 200 Non-async search timeout (ms)
async v:true Use asynchronous searching
async_timeout 3000 Async search timeout (ms)
async_minlines 1000 Min lines to trigger async search
highlight v:true 'false' to disable menu highlighting (for performance)
ctrl_np v:false <C-n/p> selects menu when 'true'; otherwise, recalls history

Important

  1. Searching large files will not cause any lag. By default, searching is concurrent. Even though no external jobs are used, a timer pauses the task at regular intervals to check if there are pending keys on the typehead.
  2. When searching across line boundaries (\n), search highlighting will be turned off.

Applying Configuration

To apply your configuration:

call g:VimSuggestSetOptions(s:vim_suggest)

If you are using vim-plug you may have to do:

autocmd VimEnter * call g:VimSuggestSetOptions(s:vim_suggest)

Global Enable/Disable

Enable or disable VimSuggest globally:

:VimSuggestEnable   " Enable VimSuggest
:VimSuggestDisable  " Disable VimSuggest

Highlighting

VimSuggest uses custom highlight groups:

  • VimSuggestMatch: Highlights matched portion of the text. Linked to PmenuMatch by default.
  • VimSuggestMatchSel: Highlights matched text in the selected item of the menu. Linked to PmenuMatchSel by default.
  • VimSuggestMute: Highlights passive text like line numbers in grep output. Linked to NonText by default.

Customization Examples

" Customize popup window appearance
let s:vim_suggest.cmd.popupattrs = {
    \ 'borderchars': ['', '', '', '', '', '', '', ''],
    \ 'borderhighlight': ['Normal'],
    \ 'highlight': 'Normal',
    \ 'border': [1, 1, 1, 1],
    \ }

" Exclude specific patterns from completion
"   To exclude :[N]b[uffer][!] and :[N]sb[uffer][!] do:
let s:vim_suggest.cmd.exclude = [
    \ '^\s*\d*\s*b\%[uffer]!\?\s\+',
    \ '^\s*\d*\s*sb\%[uffer]!\?\s\+'
    \ ]

" Optional: Customize highlight groups
highlight VimSuggestMatch ctermfg=Green guifg=#00FF00
highlight VimSuggestMatchSel cterm=bold gui=bold ctermfg=Green guifg=#00FF00
highlight VimSuggestMute ctermfg=Gray guifg=#808080

" Apply the configuration
call g:VimSuggestSetOptions(s:vim_suggest)

Key Bindings

When the popup window is open, you can use the following key mappings:

Key Action
<PageDown> Scroll down one page
<PageUp> Scroll up one page
<Tab> Move to next item
<Shift-Tab> Move to previous item
<Esc> or <Ctrl-c> Close popup
<Ctrl-s> Dismiss auto-completion and revert to default Vim behavior
<Enter> Confirm selection
<Ctrl-j> Open file selection in a split window
<Ctrl-v> Open file selection in a vertical split
<Ctrl-t> Open file selection in a new tab
<Ctrl-q> Send items (grep lines or file paths) to the quickfix list
<Ctrl-l> Send items (file paths) to the argument list
<Ctrl-g> Copy items to system clipboard (+ register)

Note: Keys used in command-line editing (:h cmdline-editing) remain unmodified.

Tip

  1. If no item is selected, pressing <Enter> selects the first menu item (works only for 'addons' commands).
  2. To automatically open the quickfix list after using <Ctrl-q>, add the following to your .vimrc:
    augroup vimsuggest-qf-show
        autocmd!
        autocmd QuickFixCmdPost clist cwindow
    augroup END
  3. To perform a multi-word search using the / or ? command, type the first word followed by <Space> to trigger auto-completion for the next word. At the end of a line, press \n to continue the search on the next line. Note that enabling the fuzzy search option will disable multi-word search functionality.

Addons

When the addons option is set to v:true, the following commands are made available. You can use these commands directly or map them to your preferred keys.

  1. Fuzzy Find Files

    :VSFind [dirpath] [fuzzy_pattern]

    This runs the system's find program (or alternatives) asynchronously to gather files for fuzzy searching. The optional first argument is the directory to search within.

    Example key mappings:

    nnoremap <key> :VSFind<space>
    nnoremap <key> :VSFind ~/.vim<space>
    nnoremap <key> :VSFind $VIMRUNTIME<space>

    The 'find' program can be specified through the g:vimsuggest_fzfindprg variable. If this variable is not defined, a default command is used (that ignores hidden files and directories). The placeholder "$*" is allowed to specify where the optional directory argument will be included. If placeholder is not specifed, directory name is included at the end. Environment variables and tilde are expanded for directory names.

    let g:vimsuggest_fzfindprg = 'find $* \! \( -path "*/.*" -prune \) -type f -follow'
    let g:vimsuggest_fzfindprg = 'fd --type f .'

    (Optional) To execute the program through a shell:

    let g:vimsuggest_shell = true
    set shell=/bin/sh
    set shellcmdflag=-c

    Performance:

    Using the system's find program significantly outperforms Vim's :find command. On the Vim source repository, it takes ~1 second to list all files using :find **/* command, while :VSFind takes ~30 milliseconds (30x faster). Most of the gains come from avoiding the shell's recursive glob wildcard.

  2. Fuzzy Search Buffers and Other Vim Artifacts

    :VSBuffer [fuzzy_pattern]
    :VSMru [fuzzy_pattern]
    :VSKeymap [fuzzy_pattern]
    :VSMark [fuzzy_pattern]
    :VSRegister [fuzzy_pattern]
    :VSChangelist [fuzzy_pattern]
    
    • VSKeymap opens the file containing the keymap when pressed.
    • VSRegister pastes the register's content.
    • Other commands behave as expected.
    • VSMru lists files from v:oldfiles.

    Example key mapping:

    nnoremap <key> :VSBuffer<space>
  3. Live Grep Search

    :VSGrep {pattern} [directory]

    Executes a grep command live, showing results as you type. {pattern} is given directly to grep command, and it's best to enclose it in quotes to handle special characters. You can also specify an optional directory.

    Example key mappings:

    nnoremap <key> :VSGrep ""<left>
    nnoremap <key> :VSGrep "<c-r>=expand('<cword>')<cr>"<left>

    The grep program is taken from g:vimsuggest_grepprg variable or the :h 'grepprg' option. If it contains $*, it gets replaced by the command-line arguments. Otherwise, arguments are appended to the end of the command.

    let g:vimsuggest_grepprg = 'grep -REIHins $* --exclude-dir=.git --exclude=".*"'
    let g:vimsuggest_grepprg = 'rg --vimgrep --smart-case'
    let g:vimsuggest_grepprg = 'ag --vimgrep'
  4. Live File Search

    :VSFindL {pattern} [directory]

    This command runs system's find program live, showing results as you type. {pattern} is a glob (or regex) pattern that should be enclosed in quotes if it contains wildcards. The find command is customized via g:vimsuggest_findprg (similar to g:vimsuggest_fzfindprg).

    Example key mapping and configuring 'find' program:

    nnoremap <key> :VSFindL "*"<left><left>
    let g:vimsuggest_findprg = 'find -EL $* \! \( -regex ".*\.(swp\|git)" -prune \) -type f -name $*'
    let g:vimsuggest_findprg = 'fd --type f'
  5. In-Buffer Search (:h :global)

    :VSGlobal {regex_pattern}

    Use this for a powerful in-buffer search with Vim's regex. For example, to list all functions and classes in a Python file and jump quickly:

    nnoremap <buffer> <key> :VSGlobal \v(^\|\s)(def\|class).{-}
  6. Search in Included Files (:h include-search)

    :VSInclSearch {regex_pattern}

    Similar to VSGlobal, but searches for symbols (ignoring comments) in both the current buffer and included files. The results are gathered using the :ilist command.

    Example key mapping:

    nnoremap <key> :VSInclSearch<space>
  7. Execute Shell Command

    :VSExec {shell_command}

    This command runs any shell command using your $SHELL environment, allowing features like brace expansion and globbing. Errors are ignored. However, :VSGrep and VSFindL commands are less clunky.

    Example key mappings:

    nnoremap <key> :VSExec grep -RIHins "" . --exclude-dir={.git,"node_*"} --exclude=".*"<c-left><c-left><c-left><left><left>
    " Easier to type but low performance:
    nnoremap <key> :VSExec grep -IHins "" **/*<c-left><left><left>

Important

External programs are executed directly if g:vimsuggest_shell is v:false. Otherwise, they are executed through shell as specified in shell option (:h 'shell'). Using shell allows for expansion of ~, $VAR, ** (if your shell supports), etc.

let g:vimsuggest_shell = v:true
set shell=/bin/zsh
set shellcmdflag=-c

See also :h expandcmd()

Tip

If these commands aren't sufficient, you can define your own using the examples provided in autoload/vimsuggest/addons/addons.vim script. Legacy script users can import using :import also (see :h import-legacy).

Other Plugins

For insert-mode auto-completion, try Vimcomplete.

Contributing

Open an issue if you encounter problems. Pull requests are welcomed.