vindent.vim
is Vim/Neovim plugin that provides indentation related motions and text objects:
This plugin is inspired by vim-indentwise
and vim-indent-object.
vindent.vim
is essentially a combination and reimplementation of the two
plugins, but improved! Here are some of the improvements and reasons why
you should switch to vindent.vim
:
{count}
s and normal commands such as
d
, c
, and y
. Works just like a native vim motion!Install using your favourite plugin manager, or use Vim's built-in package support:
mkdir -p ~/.vim/pack/jessekelighine/start
cd ~/.vim/pack/jessekelighine/start
git clone https://github.com/jessekelighine/vindent.vim
vindent.vim
comes with no default keybindings.
Here is a recommended set of keybindings to put in your .vimrc
/init.vim
:
let g:vindent_motion_OO_prev = '[=' " jump to prev block of same indent.
let g:vindent_motion_OO_next = ']=' " jump to next block of same indent.
let g:vindent_motion_more_prev = '[+' " jump to prev line with more indent.
let g:vindent_motion_more_next = ']+' " jump to next line with more indent.
let g:vindent_motion_less_prev = '[-' " jump to prev line with less indent.
let g:vindent_motion_less_next = ']-' " jump to next line with less indent.
let g:vindent_motion_diff_prev = '[;' " jump to prev line with different indent.
let g:vindent_motion_diff_next = '];' " jump to next line with different indent.
let g:vindent_motion_XX_ss = '[p' " jump to start of the current block scope.
let g:vindent_motion_XX_se = ']p' " jump to end of the current block scope.
let g:vindent_object_XX_ii = 'ii' " select current block.
let g:vindent_object_XX_ai = 'ai' " select current block + one extra line at beginning.
let g:vindent_object_XX_aI = 'aI' " select current block + two extra lines at beginning and end.
let g:vindent_jumps = 1 " make vindent motion count as a |jump-motion| (works with |jumplist|).
Note: Be sure to put the key-bindings BEFORE the plugins are loaded, e.g., before
packloadall
from Vim/NeoVim (:h plugin
),call plug#begin()
from vim-plug,lua require("init")
from NeoVim
(if you load plugins with something like
packer.nvim or
lazy.nvim in init.lua
)init.lua
exclusively,
wrap the above in vim.cmd
and put it before something like
require("lazy").setup
from lazy.nvim
or require('packer').startup
from packer.nvim.
(See this comment for example)With these keybindings, you can now...
[=
/]=
. (examples)[-
/]-
. (examples)[+
/]+
. (examples)[;
/];
. (examples)[p
/]p
. (examples)ii
(in indent),ai
(an indent), and aI
(an Indent). (examples)Feel free to customize the keybindings. If you wish not to use a certain functionality, simply leave the corresponding variable undefined.
These motions are very self explanatory: move to the previous or next line with
either same, less, more, or different indentation. These motions
operates on entire lines if it is prepended with a normal command such as d
or c
or y
.
For example, assume that the keybindings in Usage are used and consider the following python code:
1 def SumTo():
2 print("Hello, what do you want to sum?")
3 count = int(input("integer:"))
4
5 total = 0
6 for i in range(count+1):
7 total += i
8
9 print(f"This is your total: {total}")
10 return(total)
[-
moves it to line 1.2[-
moves it to line 1.[+
moves it to line 7.2]+
moves it to line 7.See doc
section vindent_Motion
for more detail and
examples.
These motions move the cursor to the previous or next text block with the same
indentation. All vindent motions and objects that operates block-wise contains
a two character string of O
's and X
's in their names. This string indicates
how the motion or object defines a "text block". More precisely, they
are all named vindent_motion_<A1><A2>_<A3>
or vindent_object_<A1><A2>_<A3>
where...
<A1>
indicates whether "empty lines" are IGNORED when finding the
boundaries of a "text block".<A2>
indicates whether "lines with more indentation" are IGNORED when
finding the boundaries of a "text block".<A3>
indicates the type of motion or text object.That is,
<A1><A2> |
"Empty lines" ignored? | "More-indented lines" ignored? |
---|---|---|
OO |
No | No |
XO |
Yes | No |
OX |
No | Yes |
XX |
Yes | Yes |
Here are some examples to clear things up. Assume that the keybindings in Usage are used and consider the following code:
1 function! SumTo(number)
2 let l:sum = 0
3 for l:time in range(a:number)
4 echom "This is the" l:time "time."
5 let l:sum = l:count + l:time
6 endfor
7
8 echom "The sum is" l:sum
9 return "Hi" . a:name
10 endfunction
If the cursor is on line 2, then pressing ]=
2 times moves the cursor to line
6 and 8. This is because ]=
is mapped to g:vindent_motion_OO_next
, in
which OO
indicates that "empty lines" and "more-indented lines" are all
considered to be boundaries of a text block (NOT ignored).
If the cursor is on line 2, then pressing ]p
moves the cursor to line 9.
This is because ]p
is mapped to g:vindent_motion_XX_se
, in which XX
indicates
that "empty lines" and "more-indented lines" are all ignored, thus line 2 to
line 9 is considered to be one text block.
Note:
g:vindent_motion_OO_prev
and g:vindent_motion_OO_next
is what
most people want, since every breakage of continuous lines with same
indentation are considered a boundary. But feel free to change OO
to
whatever setting you find the most useful.g:vindent_motion_XX_ss
and g:vindent_motion_XX_se
.doc
for more details.The text objects are:
Text Object | Mnemonics | Description |
---|---|---|
ii |
in indent | select text block of same indentation. |
ai |
an indent | select text block of same indentation and a previous line with less indentation. |
aI |
an Indent | select text block of same indentation and a previous and a next line with less indentation. |
Similar to block-wise motions, you can specify
what is considered to be the same block by changing the O
's and X
's in the
variable name.
The text objects can take counts, which indicates how make levels up (of indents) should be selected. Assume that the keybindings in Usage are used and consider following code:
1 function! SumTo(number)
2
3 let l:sum = 0
4 for l:time in range(a:number)
5 echom "This is the" l:time "time."
6 let l:sum += l:time
7 endfor
8
9 echom "The sum is" l:sum
10 return l:sum
11 endfunction
vii
selects lines 3--10.vai
selects lines 1--10.vaI
selects lines 1--11.v2ii
selects lines 3--10. (one indent level up)v2ai
selects lines 1--10. (one indent level up, and then search for a previous line with less indentation)If you think pressing 2
for "one indent level up" is not very intuitive,
you can put let g:vindent_count = 0
in your .vimrc
/init.vim
.
This setting would change how {count}
's are handled as such:
v1ii
selects lines 3--10. (one indent level up)v1ai
selects lines 1--10. (one indent level up, and then search for a previous line with less indentation)For more details please refer to the doc
, section vindent_Text_Object
.
Here are some gobal settings. Simply set the variables with the keybindings as shown in Usage. You can use the corresponding command listed above to toggle the settings on the fly.
Setting/Variable | Value | Description | Command to Toggle Setting |
---|---|---|---|
g:vindent_begin |
0 or 1 (default: 1 ) |
whether to move cursor to the beginning of line after a vindent motion | :VindentBegin |
g:vindent_count |
0 or 1 (default: 1 ) |
see the end of section Vindent Text Objects | |
g:vindent_jumps |
0 or 1 (default: 0 ) |
whether a vindent motion is added to the jumplist | :VindentJumps |
g:vindent_noisy |
0 or 1 (default: 0 ) |
whether vindent motion throws an error if the cursor does not move | :VindentNoisy |
g:vindent_infer |
0 or 1 (default: 0 ) |
whether vindent tries to infer indentation of empty lines by context | :VindentInfer |
g:vindent_block_ending |
a list of strings (default: undefined) | tells vindent.vim which patterns are considered to be end of code blocks when trying to infer indentation of empty lines (see below) |
If g:vindent_infer
is set to 1
and g:vindent_block_ending
is left undefined,
then vindent will guess the indentation of empty lines by using the max indentation of nearby lines;
If g:vindent_block_ending
is also defined,
then vindent will try to infer indentation by checking whether the current empty line is at the edge of a code block.
An example of g:vindent_block_ending
would be:
let g:vindent_block_ending = [ ')', ']', '}', 'end', 'else', 'elif' ]
For more details please refer to the doc
, section vindent_Miscellaneous
.
Distributed under the same terms as Vim itself. See :help license
.