113

Github GitHub - gelguy/wilder.nvim: A more adventurous wildmenu

 3 years ago
source link: https://github.com/gelguy/wilder.nvim
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

wilder.nvim

A more adventurous wildmenu

wilder.nvim adds new features and capabilities to wildmenu.

  • Automatically provides suggestions as you type
    • : cmdline support - autocomplete commands, expressions, filenames, etc.
    • / search support - get search suggestions from the current buffer
  • High level of customisation
    • build your own custom pipeline to suit your needs
    • customisable look and appearance
  • Async query support - uses Python 3 remote plugin for faster and non-blocking queries

Requirements

  • Vim 8.1+ or Neovim 0.3+
  • Python support only in Neovim
  • Floating window support only in Neovim 0.4+

Install

" with dein
call dein#add('gelguy/wilder.nvim')

" with vim-plug
" :UpdateRemotePlugins needed
Plug 'gelguy/wilder.nvim'

Usage

Getting started

Start with the following minimal configuration in your init.vim or .vimrc:

call wilder#enable_cmdline_enter()
set wildcharm=<Tab>
cmap <expr> <Tab> wilder#in_context() ? wilder#next() : "\<Tab>"
cmap <expr> <S-Tab> wilder#in_context() ? wilder#previous() : "\<S-Tab>"

" only / and ? are enabled by default
call wilder#set_option('modes', ['/', '?', ':'])

When in : cmdline mode, wildmenu suggestions will be automatically provided. When searching using /, suggestions will be provided. The default uses substring matching.

Use <Tab> to cycle through the list forwards, and <S-Tab> to move backwards.

Customising the pipeline

Use wilder#set_option('pipeline', <pipeline>) to customise the pipeline. For example, in Neovim, to use fuzzy matching instead of substring matching:

" For Neovim only
" For wild#cmdline_pipeline():
"   'language'   : set to 'python' to use python
"   'fuzzy'      : set fuzzy searching
" For wild#python_search_pipeline():
"   'pattern'    : can be set to wilder#python_fuzzy_delimiter_pattern() for stricter fuzzy matching
"   'sorter'     : omit to get results in the order they appear in the buffer
"   'engine'     : can be set to 're2' for performance, requires pyre2 to be installed
call wilder#set_option('pipeline', [
      \   wilder#branch(
      \     wilder#cmdline_pipeline({
      \       'language': 'python',
      \       'fuzzy': 1,
      \     }),
      \     wilder#python_search_pipeline({
      \       'pattern': wilder#python_fuzzy_pattern(),
      \       'sorter': wilder#python_difflib_sorter(),
      \       'engine': 're',
      \     }),
      \   ),
      \ ])

The pipeline is a list of functions (referred to as pipes) which are executed in order, passing the result of the previous function to the next one. wilder#branch() is a higher-order pipe which is able to provide control flow given its own lists of pipelines.

See the docs at :h wilder-pipeline for a more details.

Here are some more example pipelines:

History

call wilder#set_option('pipeline', [
      \   wilder#branch(
      \     [
      \       wilder#check({_, x -> empty(x)}),
      \       wilder#history(),
      \     ],
      \     wilder#cmdline_pipeline(),
      \     wilder#search_pipeline(),
      \   ),
      \ ])

When the cmdline is empty, provide suggestions based on the cmdline history (:h cmdline-history).

With a Devicons font:

call wilder#set_option('pipeline', [
      \   wilder#branch(
      \     [
      \       wilder#check({_, x -> empty(x)}),
      \       wilder#history(),
      \       wilder#result({
      \         'draw': [{_, x -> ' ' . x}],
      \       }),
      \     ],
      \     wilder#cmdline_pipeline(),
      \     wilder#search_pipeline(),
      \   ),
      \ ])

File finder (Experimental) (Neovim only)

" 'file_command' : for ripgrep : ['rg', '--files']
"                : for fd      : ['fd', '-tf']
" 'dir_command'  : for fd      : ['fd', '-td']
" 'filters'      : use ['cpsm_filter'] for performance, needs cpsm to be installed
call wilder#set_option('pipeline', [
      \   wilder#branch(
      \     wilder#python_file_finder_pipeline({
      \       'file_command': ['find', '.', '-type', 'f', '-printf', '%P\n'],
      \       'dir_command': ['find', '.', '-type', 'd', '-printf', '%P\n'],
      \       'filters': ['fuzzy_filter', 'difflib_sorter'],
      \     }),
      \     wilder#cmdline_pipeline(),
      \     wilder#python_search_pipeline(),
      \   ),
      \ ])

When getting file completions, fuzzily search and match through all files under the project directory. Has to be placed above wilder#cmdline_pipeline().

To optimise for performane, the file_command, dir_command and filters options can be customised. See :h wilder#python_file_finder_pipeline() for more details.

Customising the renderer

Use wilder#set_option('renderer', <renderer>) to change how wilder draws the results. By default, wilder tries its best to look like the default wildmenu.

Wildmenu renderer

wilder#wildmenu_renderer() draws the candidates above the cmdline. For Neovim 0.4+, a floating window is used. Otherwise the statusline is used. Due to statusline limitations, the wildmenu only fills up the width of the current window.

" 'highlighter' : applies highlighting to the candidates
call wilder#set_option('renderer', wilder#wildmenu_renderer({
      \ 'highlighter': wilder#basic_highlighter(),
      \ }))

An alternative theme which shows a spinner and the current number of items:

call wilder#set_option('renderer', wilder#wildmenu_renderer({
      \ 'highlighter': wilder#basic_highlighter(),
      \ 'separator': ' · ',
      \ 'left': [' ', wilder#wildmenu_spinner(), ' '],
      \ 'right': [' ', wilder#wildmenu_index()],
      \ }))

For Airline and Lightline users, wilder#wildmenu_airline_theme() and wilder#wildmenu_lightline_theme() can be used.

" use wilder#wildmenu_lightline_theme() if using Lightline
" 'highlights' : can be overriden, see :h wilder#wildmenu_renderer()
call wilder#set_option('renderer', wilder#wildmenu_renderer(
      \ wilder#wildmenu_airline_theme({
      \   'highlights': {},
      \   'highlighter': wilder#basic_highlighter(),
      \   'separator': ' · ',
      \ })))

Popupmenu renderer (Experimental) (Neovim only)

For Neovim 0.4+, wilder#popupmenu_renderer() can be used to draw the results on a popupmenu, similar to wildoptions+=pum.

" 'highlighter' : applies highlighting to the candidates
call wilder#set_option('renderer', wilder#popupmenu_renderer({
      \ 'highlighter': wilder#basic_highlighter(),
      \ }))

Use wilder#renderer_mux() to choose which renderer to use for different cmdline modes. This is helpful since the popupmenu might overlap the current window when searching with /.

call wilder#set_option('renderer', wilder#renderer_mux({
      \ ':': wilder#popupmenu_renderer({
      \   ... settings ...
      \ }),
      \ '/': wilder#wildmenu_renderer({
      \   ... settings ...
      \ }),
      \ }))
Devicons for popupmenu

Uses ryanoasis/vim-devicons by default. To use other plugins, the get_icon option can be changed. See :h wilder#popupmenu_devicons for more details.

call wilder#set_option('renderer', wilder#popupmenu_renderer({
      \ 'highlighter': wilder#basic_highlighter(),
      \ 'left': [
      \   wilder#popupmenu_devicons(),
      \ ],
      \ }))

Fuzzy highlighting

The highlighter option for both wilder#wildmenu_renderer() and wilder#popupmenu_renderer() can be changed for better fuzzy highlighting.

" Neovim only
" For lua_pcre2_highlighter : requires `luarocks install pcre2`
" For lua_fzy_highlighter   : requires fzy-lua-native vim plugin found
"                             at https://github.com/romgrk/fzy-lua-native
call wilder#set_option('renderer', wilder#popupmenu_renderer({
      \ 'highlighter': [
      \   wilder#lua_pcre2_highlighter(),
      \   wilder#lua_fzy_highlighter(),
      \ ],
      \ }))

Other available highlighters are wilder#python_pcre2_highlighter() and wilder#python_cpsm_highlighter() which needs cpsm to be installed.

Reducing input latency

Input latency when typing in the cmdline is due to wilder rendering synchronously. Rendering time increases for each wilder#wildmenu_renderer() item, wilder#popupmenu_renderer() column, or by having a slow highlighter.

Use minimal configuration

The fastest configuration for wilder is to use the non-fuzzy Python pipelines and the default renderers.

" Neovim only
call wilder#set_option('pipeline', [
      \   wilder#branch(
      \     wilder#cmdline_pipeline({'language': 'python'}),
      \     wilder#python_search_pipeline(),
      \   ),
      \ ])

" The wildmenu renderer is faster than the popupmenu renderer.
" By default no highlighting is applied.

" call wilder#set_option('renderer', wilder#popupmenu_renderer())
call wilder#set_option('renderer', wilder#wildmenu_renderer())

If this configuration is still not fast enough, the available options are to implement a faster renderer e.g. using Lua or to improve the current rendering code.

If highlighting is important, use the Lua highlighters for best performance.

Avoid wilder#wildmenu_spinner() and wilder#popupmenu_spinner() as they cause frequent re-renders.

Use debounce

Use wilder#debounce() or the debounce option in pipelines to avoid rendering too often. The debounce option is currently supported by wilder#search_pipeline() (both vim and python), wilder#cmdline_pipeline() and wilder#python_file_finder_pipeline(). The debounce interval is in milliseconds.

There is a tradeoff in increased latency for the final result due to the debounce versus the increased input latency per character typed due to the rendering of intermediate results.

" Debounce the whole pipeline
call wilder#set_option('pipeline', [
      \ wilder#debounce(10),
      \ wilder#branch([
      \   ...
      \ ]),
      \ ])

" Or debounce individual pipelines
call wilder#set_option('pipeline', [
      \   wilder#branch(
      \     wilder#cmdline_pipeline({
      \       'debounce': 10,
      \     }),
      \     wilder#search_pipeline({
      \       'debounce': 10,
      \     }),
      \   ),
      \ ])

Faster Startup time

Define the pipeline and renderer in an autocmd so the initialisation is deferred to the first CmdlineEnter.

" Other options should be set outside
call wilder#set_option('modes', ...)

" ++once supported in Nvim 0.4+ and Vim 8.1+
autocmd CmdlineEnter * ++once s:wilder_init()

function! s:wilder_init() abort
  call wilder#set_option('pipeline', ...)
  call wilder#set_option('renderer', ...)
endfunction

Disabling in the case of errors

Use q: to open the cmdline-window and enter the following command

call wilder#disable()

Alternatively, define a mapping in your init.vim or .vimrc

nnoremap <Leader>w :call wilder#toggle()<CR>

Acknowledgements

Many thanks to the following codebases for providing ideas and reference:

Shougo/denite.nvim

junegunn/fzf.vim

vim-airline/vim-airline

itchyny/lightline.vim

nixprime/cpsm

raghur/fruzzy

Yggdroot/LeaderF

nvim-telescope/telescope.nvim

ryanoasis/vim-devicons

Xuyuanp/scrollbar.nvim

and many more!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK