laher / fuzzymenu.vim

menu system for vim/neovim, using fzf for fuzzy selection

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

fuzzymenu.vim build-status

fuzzymenu is a [preview release] menu plugin for vim or neovim, built on top of fzf, with a curated list of menu items.

Use vim more easily, but still learn vim - you won't need to memorise so many commands and mappings, BUT fuzzymenu will help by reminding you how to use those features directly, as you select a menu item. Fuzzymenu provides:

  • A single starting point for oodles of discoverable functionality (for me it's <space><space>).
  • A curated set of features - 'finding things', 'learning vim things', and 'IDE things'.
  • A fuzzy-search menu is faster and easier to use than heirarchical menus.
  • Use vim better, faster:
    • Use vim in the usual way, AND like an IDE (e.g. LSP integration for semantic code navigation; also, menu items contain 'IDE lingo' keywords alongside the vim terminology).
    • Learn to use vim features (e.g. text objects and motions) with searchable prompts.
    • Extend the functionality by adding more items, and telling fuzzymenu about custom text objects.

This is still a preview version - I think it’s very useful already - please try it out.

Intro video

Here's an intro to an early version of fuzzymenu (watch on youtube.com).

Intro to fuzzymenu

It's 10 minutes - wow I spoke a lot. If that sounds like too much, just install, below, and hit <leader><leader> to start playing.

Install

Install fuzzymenu and dependencies using your preferred plugin manager.

For example, using vim-plug:

Plug 'junegunn/fzf'
Plug 'junegunn/fzf.vim'
Plug 'laher/fuzzymenu.vim'

Then, for convenience, a mapping starting with Ctrl key is preferable, as it works in different modes

  nmap <silent> <C-space> <Plug>(Fzm)
  vmap <silent> <C-space> <Plug>(FzmVisual)
  • The fzf plugin itself depends on a binary file fzf. If you don't have it already, :call fzf#install() (or see fzf docs).

Usage

See also help docs - especially for function signatures.

1. Invoke fuzzymenu

You can invoke fuzzymenu with the above mapping if set, or a command :Fzm (fullscreen with :Fzm!).

  • Also try :FzmOps for guided normal-mode operations on text objects.

2. Using the menu

2a. using fzf

fuzzymenu uses the fzf user interface.

  • Type some letters to filter the menu contents.
  • fzf will match entries containing the letters you type, BUT they don't need to appear consecutively in the target menu entry.
  • e.g. Typing cnsctv would match an entry named consecutive.
  • e.g.2. vto would not match - those letters do exist in the word consecutive, but in a different order.
  • fzf uses case-insensitive fuzzy search.
  • Use Up/Down arrows (or k/j), to select the item you want.
  • Press Enter to select the item, which may be another fzf entry, in some cases.
  • To cancel, Esc/Ctrl-C/:q to cancel.
  • fuzzymenu now respects g:fzf_layout. Note that not all layouts play nicely with fuzzymenu's alignment. If your fzf_layout doesn't seem to suit fuzzymenu, try configuring the numeric g:fuzzymenu_align_adjust, to adjust the right-aligned commands to the left (use a negative number) or right (a number greater than 0).

2b. Fuzzymenu specifics:

Fuzzymenu entries are intended to be easy to search for:

  • You can search using the name of the item (which may be specified by 'general IDE terminology' AND 'vim terminology'. e.g. 'search buffers' vs 'Find in open files').
  • search using part of the command name which will be executed.
  • Search by entry [tags].
  • If you want to search for a combination of these, then order is important - [tag]name :command.

3. Learning vim through fuzzymenu

Fuzzymenu isn't a general purpose vim helper. Try vimtutor and many other resources. However, fuzzymenu does make a small effort to teach you how to use its content directly...

  • Please see the 'definition' on the right of each menu item - the definition is also searchable.
  • Menu items use one of four types of invocation:
    • Commands. From normal mode, type :, e.g. :Helptags
    • Function calls. From normal mode, type :call , e.g. :call func#name()
    • Normal mode input sequence. From normal mode, just type the sequence, e.g. ggVG
    • Interactive (multi-step) features (typically using fzf or a basic prompt). Where appropriate the normal-mode sequence will be shown (e.g. try 'yank')
  • Use :Fzm -> help (another fzf menu, :Helptags) to navigate vim's help system more easily.

Bundled menu items

fuzzymenu comes with a GROWING list of menu items (please submit more via pull requests).

  • Some interactive helpers for normal-mode commands & text-objects (yank, delete, change some text).
  • Various commands from fzm.vim.
  • Various LSP features (requires one of these):
    • vim-lsp: go to definition/implementation/references. rename, format, organize imports).
    • Coc.nvim: similar to vim-lsp
  • Various git features (requires fugitive ).
  • Various go tools (requires vim-go or gothx.vim ).
  • A few fundamentals: setting case-[in]sensitive searches, show/hiding line numbers and whitespace characters.
  • Configuring vim itself (mapping keys; some common settings and options)
Area Dependencies Registered by fuzzymenu Registered by dependency
fundamentals n/a [x]
operators & text objects n/a [x]
vim config n/a [x]
FZF (fzf, fzf.vim) [x]
LSP vim-lsp OR Coc.nvim [x]
Go vim-go [x]
Go gothx [x]
git fugitive [x]

More to follow... For example, I'm keen to support multiple providers for given features ... for LSP, this could include vim-lsp, coc.vim & languageclient-neovim. For Go, gothx.vim and vim-go.

Configuring vim with Fuzzymenu

Fuzzymenu supplies some functionality to update your vim config. Fuzzymenu can add key mappings, and can update your general config

  • This is powerful because it allows you to change your vim setup on-the-fly, as with a typical GUI text editor.
  • WARNING: but note - if you let fuzzymenu write your config, then please acknowledge that its's not a fool-proof system.
    • Do not mix-and-match your hand-written config files with fuzzymenu's generated config.
    • fuzzymenu matches and replaces text based on some rudimentary parsing (regexes). Don't let it edit a file containing any sophisticated viml, it could end up doing bad things to your vim.

Approach:

  • fuzzymenu updates a specific vim config file (called ~/.vimrc.fuzzymenu by default, but you can change it using g:fuzzymenu_write_config).
  • fuzzymenu sources this file (you can source it yourself if you prefer from your .vimrc/init.vim, if you prefer)

Note, you can disable fuzzymenu's writing of this file, by setting set g:fuzzymenu_write_config_autowrite=0

Extend fuzzymenu.vim

There are a few ways you can introduce your own entries...

  1. Create entries in your own .vimrc (or init.vim) file
  2. Submit a PR with additional menu items for this project. If it seems useful I will probably approve it.
  3. Define mappings in your own plugin, which can be loaded whenever fuzzymenu.vim is installed.

Defining entries

Adding an entry to your vimrc, looks like one of these 3 examples:

call fuzzymenu#Add('FZF: Key mappings', {'exec': 'Maps', 'after': 'call fuzzymenu#InsertMode()', 'help': 'vim key mappings'})
call fuzzymenu#Add('Select all', {'exec': 'normal! ggVG'})
call fuzzymenu#Add('LSP: rename', {'exec': 'LspRename', 'for': { 'exists': 'g:lsp_loaded' }})

The first parameter is a unique key. The second parameter is a map of options:

  • exec is mandatory. This is the command which will be invoked. For example, 'Maps' above is the same as running :Maps from normal mode. Use call MyFunction() to run a function. Use normal! to run some normal mode commands.
  • after is optional. Fuzzymenu runs this command after this command. It is not printed in the fzf entry. For example, if you need fuzzymenu to drop into insert mode after running your command, specify 'after': 'call fuzzymenu#InsertMode()'. Insert mode is necessary for fzf features.
  • help is for adding an additional explanation.
  • for specifies a filetype.

Limitations

There will be some things which aren't well supported yet.

  • One example: the menu item's 'exec' is triggered inside an fzf 'sink' function. For many operations, this is fine, but in some cases the context of the invocation might pick up some context from fzf's popup window.

For example, an 'exec' with <c-r><c-w>, such as 'GGrep ', will try to find the word under the cursor of the fzf popup window, rather than the originating buffer.

For now the workaround is to wrap the fzf call into a function that uses expand("<cword>"). See fuzzymenu#GitGrepUnderCursor(), for example.

Configuration

See ./doc/fuzzymenu.vim.txt for configuration options ...

For contributors

Some guidance for anyone wanting to contribute ...

  1. I'm keen to implement menu entries for particular areas of functionality:
  • Fundamentals - any more general purpose tools like 'set nonumber', where the naming is not intuitive? Give it a more intuitive key name (fuzzymenu will still find it by the original name if necessary).
  • LSP clients - keen to add coc, LanguageClient-neovim, etc.
  • FZF - any more useful fzf-based commands? Happy to add the definitions here.
  • Language-specific features ... BUT I'd prefer NOT to include language-specific features whenever LSP has an equivalent.
  1. I'd like to extend the usefulness of the plugin a little:
  • Hint the ':help' for a given entry
  • Show key mappings for a given entry

I'd love to make these available as a preview window. I'm not exactly sure how to do that (typically fzf.vim uses an external program - a wrapper around cat/bat. I don't know how to print a vim help from an external command - vim/view or otherwise...). Alternatively, it might just work to implement a key mapping within the fzf window, to view help/mappings for a menu item - including some visual cue.

Defining an entry from your plugin

A plugin can add some entries to fuzzymenu, but just make sure to add them only when fuzzymenu is installed. Like this (for an imaginary plugin teddyplugin, which works on .ted files):

if exists('g:fuzzymenu_loaded')
  call fuzzymenu#Add('teddy bingo', {'exec': 'TddyBingo', 'for': {'ft': 'ted'}})
endif

From within your plugin, please use a central plugin/*.vim file to define filetype-specific mappings (rather than ftplugin/). fuzzymenu will look after which entries to show based on the for parameter and the filetype. It's just how fuzzymenu's registration mechanism works.

Background

  • I've always felt that vim could be made more intuitive - this is my first attempt.
  • The project was inspired by a combination of fzf (fuzzy finders) and spacemacs/(spacevim), and Intellij's 'shift-shift' omni finder - providing an easily discoverable feature set, where you only need to remember a single key mapping.
  • The advantage of a fuzzy menu is the immediacy of a large, filterable, top-level menu.

Status, Plans & TODOs

Status

Fuzzymenu is already meant to be useful but pretty early in terms of where I'd like it to go. Some signatures and data structures may change, and documentation is incomplete. It's alpha, and I'm working on it sporadically. Don't expect this to be 'Beta' in 2020. Maybe 2021.

Some other planned features:

  • Menu Items:
  • Interactive (2-step) normal mode commands (yank,delete,change,...) + motions/objects
  • Interactive search/replace for regions/files/next/...
  • Macro support
  • Registers? (or maybe vim-peekaboo integration if it's too hard)
  • More LSP clients (coc, languageclient-neovim, ...)
  • visual mode & ranges - prompt how?
  • writing config
  • UX
  • Per-menu-item help with <c-h> or something (maybe even a preview window?)
  • Probably redesign the layout of a line
  • hook into vim gui menus (?)

Roadmap

See Project

About

menu system for vim/neovim, using fzf for fuzzy selection

License:MIT License


Languages

Language:Vim Script 99.3%Language:Makefile 0.7%