Skip to content
/ wheel Public

Any line in any file is only a few keys away. Quick navigation for Vim and Neovim : file groups, buffers, find, grep/edit, mru, frecency, sessions, yank, ...

License

Notifications You must be signed in to change notification settings

chimay/wheel

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Introduction

What is it ?

Wheel is a :

  • file group manager
  • session manager (tabs & windows)
  • navigation plugin
  • refactoring tool

for Vim and Neovim.

Our favorite editor has already plenty of nice navigation functions. Wheel enhances their interface by using :

  • intuitive completion with multi-pattern support for prompting functions
  • dedicated buffers, in which you can filter and select elements, besides using the full power of your editor
  • a meta-command with subcommands, actions and completion
  • edit modes, that allow you to reflect your changes in a dedicated buffer to the original file(s)

With these tools, any line in any file is only a few keys away.

All is written in lightweight, classical Vimscript. No dependency required.

What does it look like ?

History and meta-command

History & :Wheel command completion

Frecency, dedicated buffers and layers

Frecency, dedicated buffers and layers

More screenshots & screencasts

See the wheel-multimedia repository.

File groups & categories

Wheel let you organize your files by creating as many file groups as you need, add the files you want to it and quickly navigate between :

  • files of the same group
  • file groups

Note that :

  • a location contains a name, a filename, as well as a line & column number
  • a file group, in fact a location group, is called a circle
  • a set of file groups, or a category, is called a torus (a circle of circles)
  • the list of toruses is called the wheel

Currently, there are more than a thousand files in my groups, and it runs like a breeze.

Why do you need three levels of grouping ?

At first glance, managing groups with circles in a torus seems to be sufficient. But with time, the torus grows big, and a third level helps you to organize your files by groups and categories:

  • the wheel contains all the toruses
  • each torus contains a category of files, e.g.:
    • configuration, development, publication
  • each circle contains a project, e.g.:
    • kitty or vifm circles in configuration torus
    • shell or vimscript in development torus
    • tea or art in publication torus

You can also organize a torus in subprojects. For instance, in the wheel torus, I have the following groups :

  • plugin/ dir files
  • autoload/ dir files
  • doc files
  • wiki files
  • test files

A wheel that follows you

Wheel is designed to follow your workflow : you only add the files you want, where you want. For instance, if you have a organize group with agenda & todo files, you can quickly alternate them, or display them in two windows. Then, if you suddenly got an idea to tune vim, you switch to the vim group with your favorites configuration files in it. Same process, to cycle, alternate or display the files. Over time, your groups will grow and adapt to your style.

Features

The group manager is the core, but it goes far beyond that : you need a quick navigation framework to travel in the wheel, and once it is there, it’s easy to add new functionalities.

  • add
    • files from anywhere in the filesystem
    • a file in more than one group
    • file:line-1 and file:line-2 in the same group
  • may be saved in wheel file (recommended)
  • on demand loading of files
    • no slowdown of (neo)vim start
  • easy navigation
    • switch to matching tab & window if available
    • next / previous location, circle or torus
    • single or multi-pattern completion in prompting functions
    • choose file, group or category in dedicated buffer
      • filter candidates
      • selection tools
      • preview
      • folds matching wheel tree structure
      • context menus
    • auto :lcd to project root of current file
    • history of wheel files
      • anywhere
      • in same group
      • in same category
    • signs displayed at wheel locations
  • search files
    • using locate
    • using find
    • MRU files not found in wheel
    • opened buffers
    • visible buffers in tabs & windows
  • search inside files
    • grep on group files
      • navigate
      • edit mode : edit and propagate changes by writing the dedicated buffer
    • outline
      • folds headers in group files (based on fold markers)
      • markdown headers
      • org mode headers
    • tags
    • markers
    • jumps & changes lists
  • narrow
    • current file
    • all circle file with a pattern
  • yank ring using TextYankPost event
    • paste before or after, linewise or characterwise
    • switch register ring
  • reorganizing
    • wheel elements
    • tabs & windows
  • undo list
    • diff between last & chosen state
  • command output in buffer
    • :ex or !shell command
    • async shell command
    • result can be filtered, as usual
  • dedicated buffers ring to save your searches
    • layer ring in each dedicated buffer
  • batch operations
  • autogroup files by extension or directory
  • save tabs & windows in minimal session file
  • display files
    • split levels : torus, circle, location
    • split
      • vertical, golden vertical
      • horizontal, golden horizontal
      • main left, golden left
      • main top, golden top
      • grid
    • mix of above
      • circles on tabs, locations on split
      • toruses on tabs, circles on split

History

This project is inspired by :

Prerequisites

Software

  • vim >= 8.2
  • neovim >= 0.6

Basically, it assumes the existence of :map-cmd and #{...} syntax for dictionaries.

If your distribution uses an older version, you can resort to appimages :

These are fast evolving pieces of software, it's worth upgrading anyway.

Operating system

Some outer rim functions assume a Unix-like OS, like Linux or BSD :

  • async functions
  • external commands, like locate
  • mirror the wheel structure in a filesystem tree

Most of the plugin should work out of the box on other OSes, however. If you encounter some problem, please let me know.

Installation

Using vim-packager

Simply add this line after packager#init() to your initialisation file :

call packager#add('chimay/wheel', { 'type' : 'start' })

and run :PackagerInstall (see the vim-packager readme).

Using minpac

Simply add this line after minpac#init() to your initialisation file :

call minpac#add('chimay/wheel', { 'type' : 'start' })

and run :PackUpdate (see the minpac readme).

Using vim-plug

The syntax should be similar with other git oriented plugin managers :

Plug 'chimay/wheel'

and run :PlugInstall to install.

Cloning the repo in a pack-start directory

You can clone the repository somewhere in your runtime-search-path. You can get a minimal version by asking a shallow clone (depth 1) and filtering out the screenshots blobs :

mkdir -p ~/.local/share/nvim/site/pack/foo/start
cd ~/.local/share/nvim/site/pack/foo/start
git clone --depth 1 --filter=blob:none https://github.com/chimay/wheel

If you install or update with git, don't forget to run :

:helptags doc

to be able to use the inline help.

Documentation

Vim help

Your guide on the wheel tracks :

:help wheel.txt

Wiki

A wheel wiki is also available.

It is recommended to read at least the step-by-step and workflow pages, either in the wiki or in the wheel.txt file.

In wheel menu

In the help submenu of the main menu (default map : <M-w><M-m>), you have access to :

  • the inline help (wheel.txt)
  • the list of current wheel mappings
  • the list of available plug mappings
  • the list of :Wheel subcommands and actions
  • the list of autocommands of your wheel group
  • a dedicated buffer basic help
  • local buffer maps

Configuration

Wiki

For a thorough list of options, see the configuration and autocommands pages in the wiki.

Example

Here is an example of configuration :

if ! exists("g:wheel_loaded")
  " ---- DONT FORGET TO INITIALIZE DICTS BEFORE USING THEM
  let g:wheel_config                 = {}
  let g:wheel_config.project         = {}
  let g:wheel_config.storage         = {}
  let g:wheel_config.storage.wheel   = {}
  let g:wheel_config.storage.session = {}
  let g:wheel_config.maxim           = {}
  let g:wheel_config.completion      = {}
  let g:wheel_config.frecency        = {}
  let g:wheel_config.display         = {}
  let g:wheel_config.display.sign    = {}

  " ---- The bigger it is, the more mappings available
  let g:wheel_config.mappings = 10
  " ---- Prefix for mappings
  let g:wheel_config.prefix = '<M-w>'
  " ---- Locate database ; default one if left empty
  let g:wheel_config.locate_db = '~/index/locate/home.db'
  " ---- Grep command : :grep or :vimpgrep
  let g:wheel_config.grep = 'grep'

  " Marker of project root
  "let g:wheel_config.project.markers = '.git'
  "let g:wheel_config.project.markers = '.project-root'
  " List of markers
  " The project dir is found as soon as one marker is found in it
  let g:wheel_config.project.markers = ['.hg' , '.git', '.project-root']
  " Auto cd to project root if > 0
  let g:wheel_config.project.auto_chdir = 1

  " The folder where toruses and circles will be stored and read
  let g:wheel_config.storage.wheel.folder = '~/.local/share/wheel'
  " Name of the default wheel file
  let g:wheel_config.storage.wheel.name = 'wheel.vim'
  " Auto read wheel file on startup if > 0
  let g:wheel_config.storage.wheel.autoread = 1
  " Auto write wheel file on exit if > 0
  let g:wheel_config.storage.wheel.autowrite = 1
  " The folder where sessions will be stored and read
  let g:wheel_config.storage.session.folder = '~/.local/share/wheel/session'
  " Name of the default session file
  let g:wheel_config.storage.session.name = 'session.vim'
  " Auto read default session file on startup if > 0
  let g:wheel_config.storage.session.autoread = 1
  " Auto write default session file on exit if > 0
  let g:wheel_config.storage.session.autowrite = 1
  " Number of backups for wheel & session files
  let g:wheel_config.storage.backups = 5

  " ---- Maximum number of elements in history
  let g:wheel_config.maxim.history = 400
  " ---- Maximum number of elements in input history
  let g:wheel_config.maxim.input = 200

  " ---- Maximum number of elements in mru
  let g:wheel_config.maxim.mru = 300

  " ---- Maximum number of elements in yank ring
  let g:wheel_config.maxim.default_yanks = 700
  let g:wheel_config.maxim.other_yanks = 100
  " ---- Maximum lines of yank to add in yank ring
  let g:wheel_config.maxim.yank_lines = 30
  " ---- Maximum size of yank to add in yank ring
  let g:wheel_config.maxim.yank_size = 3000

  " ---- Maximum size of layer ring
  let g:wheel_config.maxim.layers = 10

  " ---- Maximum number of tabs in layouts
  let g:wheel_config.maxim.tabs = 12
  " ---- Maximum number of horizontal splits
  let g:wheel_config.maxim.horizontal = 3
  " ---- Maximum number of vertical splits
  let g:wheel_config.maxim.vertical = 4

  " ---- Completion
  let g:wheel_config.completion.vocalize = 1
  let g:wheel_config.completion.wordize = 1
  let g:wheel_config.completion.fuzzy = 0
  let g:wheel_config.completion.scores = 1

  " ---- Frecency
  let g:wheel_config.frecency.reward = 120
  let g:wheel_config.frecency.penalty = 1

  " ---- Mandala & leaf status in statusline ?
  let g:wheel_config.display.statusline = 1
  " ---- Wheel dedibuf message : one-line or multi-line
  let g:wheel_config.display.dedibuf_msg = 'one-line'
  " ---- Filter prompt in dedicated buffers
  "let g:wheel_config.display.prompt = 'wheel $ '
  "let g:wheel_config.display.prompt_writable = 'wheel # '
  " ---- Selection marker in dedicated buffers
  "let g:wheel_config.display.selection = '-> '
  " ---- Signs
  let g:wheel_config.display.sign.switch = 1
  " ---- Signs at wheel locations
  "let g:wheel_config.display.sign.settings = { 'text' : '@' }
  " ---- Signs after using Wheel interface to native navigation (buffer, marker, jump, change, tag, ...)
  "let g:wheel_config.display.sign.native_settings = { 'text' : '*' }

  let g:wheel_config.debug = 0
endif

augroup wheel
  " Clear the group
  autocmd!
  " On vim enter, for autoreading
  autocmd VimEnter * call wheel#void#init()
  " On vim leave, for autowriting
  autocmd VimLeave * call wheel#void#exit()
  " Update location line & col before leaving a window
  autocmd BufLeave * call wheel#vortex#update()
  " For the generalized alternate window command, for all windows in all tabs
  autocmd BufLeave * call wheel#caduceus#update_window()
  " Executed before jumping to a location
  autocmd User WheelBeforeJump call wheel#vortex#update()
  " Executed before organizing the wheel
  autocmd User WheelBeforeOrganize call wheel#vortex#update()
  " Executed before writing the wheel
  autocmd User WheelBeforeWrite call wheel#vortex#update()
  " Executed after jumping to a location
  "autocmd User WheelAfterJump norm zMzx
  " For current wheel location to auto follow window changes
  autocmd WinEnter * call wheel#projection#follow()
  " For current wheel location to follow on editing, buffer loading
  "autocmd BufRead * call wheel#projection#follow()
  " For current wheel location to follow on entering buffer
  "autocmd BufEnter * call wheel#projection#follow()
  " Executed after using Wheel interface to a native jump (buffer, marker, jump, change, tag, ...)
  "autocmd User WheelAfterNative call wheel#projection#follow()
  " Add current non-wheel file to MRU files
  autocmd BufRead * call wheel#attic#record()
  " To record your yanks in the yank ring
  autocmd TextYankPost * call wheel#codex#add()
augroup END

Meta-command

The :Wheel meta-command gives you access to almost all the plugin features :

:Wheel subcommand

Completion is available for subcommands. For further details, see the meta-command wiki page.

I suggest you map it to a convenient key. Example :

nnoremap <space>w :Wheel<space>

Bindings

For a thorough discussion on bindings, see the bindings page in the wiki.

Frequently used functions

Below are some bindings that you may find useful. They are included in the level 10 mappings :

let nmap = 'nmap <silent>'
let vmap = 'vmap <silent>'
" Menus
exe nmap '<m-m>          <plug>(wheel-menu-main)'
exe nmap '<m-=>          <plug>(wheel-menu-meta)'
" Sync
exe nmap '<m-i>          <plug>(wheel-info)'
exe nmap '<m-$>          <plug>(wheel-sync-up)'
exe nmap '<c-$>          <plug>(wheel-sync-down)'
" ---- navigate in the wheel
" --  next / previous
exe nmap '<m-pageup>   <plug>(wheel-previous-location)'
exe nmap '<m-pagedown> <plug>(wheel-next-location)'
exe nmap '<c-pageup>   <plug>(wheel-previous-circle)'
exe nmap '<c-pagedown> <plug>(wheel-next-circle)'
exe nmap '<s-pageup>   <plug>(wheel-previous-torus)'
exe nmap '<s-pagedown> <plug>(wheel-next-torus)'
" -- switch
exe nmap '<m-cr>        <plug>(wheel-prompt-location)'
exe nmap '<c-cr>        <plug>(wheel-prompt-circle)'
exe nmap '<s-cr>        <plug>(wheel-prompt-torus)'
exe nmap '<m-space>     <plug>(wheel-dedibuf-location)'
exe nmap '<c-space>     <plug>(wheel-dedibuf-circle)'
exe nmap '<s-space>     <plug>(wheel-dedibuf-torus)'
" -- index
exe nmap '<m-x>         <plug>(wheel-prompt-index)'
exe nmap '<m-s-x>       <plug>(wheel-dedibuf-index)'
exe nmap '<m-c-x>       <plug>(wheel-dedibuf-index-tree)'
" -- history
exe nmap '<m-home>      <plug>(wheel-history-newer)'
exe nmap '<m-end>       <plug>(wheel-history-older)'
exe nmap '<c-home>      <plug>(wheel-history-newer-in-circle)'
exe nmap '<c-end>       <plug>(wheel-history-older-in-circle)'
exe nmap '<s-home>      <plug>(wheel-history-newer-in-torus)'
exe nmap '<s-end>       <plug>(wheel-history-older-in-torus)'
exe nmap '<m-h>         <plug>(wheel-prompt-history)'
exe nmap '<m-c-h>       <plug>(wheel-dedibuf-history)'
" -- alternate
exe nmap '<c-^>          <plug>(wheel-alternate-anywhere)'
exe nmap '<m-^>          <plug>(wheel-alternate-same-circle)'
exe nmap '<m-c-^>        <plug>(wheel-alternate-same-torus-other-circle)'
" ---- navigate using Wheel interface to vim native tools
" -- buffers
exe nmap '<m-b>          <plug>(wheel-prompt-buffer)'
exe nmap '<m-c-b>        <plug>(wheel-dedibuf-buffer)'
exe nmap '<m-s-b>        <plug>(wheel-dedibuf-buffer-all)'
" -- tabs & windows : visible buffers
exe nmap '<m-v>          <plug>(wheel-prompt-tabwin)'
exe nmap '<m-c-v>        <plug>(wheel-dedibuf-tabwin-tree)'
exe nmap '<m-s-v>        <plug>(wheel-dedibuf-tabwin)'
" -- (neo)vim lists
exe nmap "<m-'>          <plug>(wheel-prompt-marker)"
exe nmap "<m-k>          <plug>(wheel-prompt-marker)"
exe nmap '<m-j>          <plug>(wheel-prompt-jump)'
exe nmap '<m-,>          <plug>(wheel-prompt-change)'
exe nmap '<m-c>          <plug>(wheel-prompt-change)'
exe nmap '<m-t>          <plug>(wheel-prompt-tag)'
exe nmap "<m-c-k>        <plug>(wheel-dedibuf-markers)"
exe nmap '<m-c-j>        <plug>(wheel-dedibuf-jumps)'
exe nmap '<m-;>          <plug>(wheel-dedibuf-changes)'
exe nmap '<m-c-t>        <plug>(wheel-dedibuf-tags)'
" ---- organize the wheel
exe nmap '<m-insert>     <plug>(wheel-prompt-add-here)'
exe nmap '<m-del>        <plug>(wheel-prompt-delete-location)'
exe nmap '<m-r>          <plug>(wheel-dedibuf-reorganize)'
" ---- organize other things
exe nmap '<m-c-r>        <plug>(wheel-dedibuf-reorg-tabwin)'
" ---- refactoring
exe nmap '<m-c-g>        <plug>(wheel-dedibuf-grep-edit)'
exe nmap '<m-n>          <plug>(wheel-dedibuf-narrow-operator)'
exe vmap '<m-n>          <plug>(wheel-dedibuf-narrow)'
exe nmap '<m-c-n>        <plug>(wheel-dedibuf-narrow-circle)'
" ---- search
" -- files
exe nmap '<m-f>          <plug>(wheel-prompt-find)'
exe nmap '<m-c-f>        <plug>(wheel-dedibuf-find)'
exe nmap '<m-c-&>        <plug>(wheel-dedibuf-async-find)'
exe nmap '<m-u>          <plug>(wheel-prompt-mru)'
exe nmap '<m-c-u>        <plug>(wheel-dedibuf-mru)'
exe nmap '<m-l>          <plug>(wheel-dedibuf-locate)'
" -- inside files
exe nmap '<m-o>          <plug>(wheel-prompt-occur)'
exe nmap '<m-c-o>        <plug>(wheel-dedibuf-occur)'
exe nmap '<m-g>          <plug>(wheel-dedibuf-grep)'
exe nmap '<m-s-o>        <plug>(wheel-prompt-outline)'
exe nmap '<c-s-o>        <plug>(wheel-dedibuf-outline)'
" ---- yank ring
exe nmap '<m-y>          <plug>(wheel-prompt-yank-plain-linewise-after)'
exe nmap '<m-p>          <plug>(wheel-prompt-yank-plain-charwise-after)'
exe nmap '<m-s-y>        <plug>(wheel-prompt-yank-plain-linewise-before)'
exe nmap '<m-s-p>        <plug>(wheel-prompt-yank-plain-charwise-before)'
exe nmap '<m-c-y>        <plug>(wheel-dedibuf-yank-plain)'
exe nmap '<m-c-p>        <plug>(wheel-dedibuf-yank-list)'
" ---- undo list
exe nmap '<m-s-u>        <plug>(wheel-dedibuf-undo-list)'
" ---- ex or shell command output
exe nmap '<m-!>          <plug>(wheel-dedibuf-command)'
exe nmap '<m-&>          <plug>(wheel-dedibuf-async)'
" ---- dedicated buffers
exe nmap '<m-tab>        <plug>(wheel-mandala-add)'
exe nmap '<m-backspace>  <plug>(wheel-mandala-delete)'
exe nmap '<m-left>       <plug>(wheel-mandala-backward)'
exe nmap '<m-right>      <plug>(wheel-mandala-forward)'
exe nmap '<c-up>         <plug>(wheel-mandala-switch)'
" ---- layouts
exe nmap '<m-z>          <plug>(wheel-zoom)'

Examples

Display matching files in splits

  • <M-w><space> to launch the location navigator
  • i to go to insert mode
  • enter the pattern you want
    • e.g. \.vim$ if all your vim locations end with .vim
  • <enter> to validate the pattern
  • * to select all the visible (filtered) locations
  • v to open all selected locations in vertical splits

More

More examples are available in the wiki examples page.

Warning

Despite abundant testing, some bugs might remain, so be careful.

About

Any line in any file is only a few keys away. Quick navigation for Vim and Neovim : file groups, buffers, find, grep/edit, mru, frecency, sessions, yank, ...

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published