Have you ever forgotten the parameters to a Python function? Or maybe you are just tired of typing the same keyword arguments over and over? Do you find yourself making typos while trying to create an instance of a class?
If so then vim-python-function-expander is here for you.
First, write our your function/class/callable object, put your cursor inside
of the ()
s, and press Tab. vim-python-function-expander will detect every
argument inside of the ()
s and insert them as text into your file, automatically.
(|x| is the location of the cursor)
Before:
import re
re.sub(|x|)
After:
import re
re.sub(pattern, repl, string, count=0, flags=0)
Here's a recording of function expansion, in-action:
Also, vim-python-function-expander comes with an "auto-trimmer" mapping. See the Auto-Trimmer section for details.
For vim-python-function-expander to work, several Vim plugins and Python packages must be installed:
- Vim must be compiled with Python support.
Vim Plugins:
-
Note: If you use Vim with Python 3, you may need to add
let g:UltiSnipsUsePythonVersion = 3
to your.vimrc
.
Python Packages:
Follow the installation instructions on each page before continuing.
-
First, install everything in Requirements if you have not already.
-
Add this repository with your preferred package manager:
Example (Using vim-plug):
Plug 'ColinKennedy/vim-python-function-expander'
Then run :PlugInstall
and restart Vim.
Or install this repository manually by cloning it and copying each of its
folder's contents to your ~/.vim
folder:
git clone /~https://github.com/ColinKennedy/vim-python-function-expander.git
Automatic parameter expansion is nice but what if the call signature is huge? You'd end up wasting valuable time deleting the parameters that you didn't need.
For example, with the re.sub example:
import re
re.sub(pattern, repl, string, count=0, flags=re.VERBOSE)
Only "flags" has non-default values. But vim-python-function-expander expands "count" and "flags". If you had a function or class with 6+ keywords and you only needed 1, you'd probably want to delete the other 5. auto-trimmer can do this for you, automatically.
Before auto-trimmer (|x| is your cursor):
import argparse
argparse.ArgumentParser(
prog=None,
usage='Some usage information',
description='My description here',
epilog=None,
version=None,|x|
parents=[],
formatter_class=HelpFormatter,
prefix_chars='-',
fromfile_prefix_chars=None,
argument_default=None,
conflict_handler='error',
add_help=True,
)
After auto-trimmer:
import argparse
argparse.ArgumentParser(
usage='Some usage information',
description='My description here',
)
Here's another quick demo:
The default mapping for the auto-trimmer is <leader>ta
. Very typically, the
workflow goes:
- Create the function call / callable object
- Position inside the
()
s - Press the UltiSnips "expand" key (for most people, this is [Tab])
- Step through and replace variables as needed
- auto-trim the function down to just its important bits with
<leader>ta
- Rinse and repeat
vim-function-python-expander has a few options and mappings that you can customize.
<leader>ta
is assigned by default to trim parameters at the current line.
To change it, add this to your ~/.vimrc
.
nmap <leader>ya <Plug>(trimmer-mapping) " Where `<leader>ya` is the mapping you want
The [Tab] key is used to expand callable objects. That is because
vim-python-function-expander uses UltiSnips for expansion. If you want to
change the expansion key to be something different, consider adding
this to your ~/.vimrc
.
let g:UltiSnipsExpandTrigger = 't' " The `t` key now expands. Default: '<tab>'
Note: It's not recommended to change the trigger to "t". It's just an example.
Variable | Default | Description |
---|---|---|
g:expander_use_local_variables | 1 | This will try to fill in optional arguments in the expanded text with variables in the current scope. if they exist. |
g:expander_full_auto | 0 | If "1" then vim-python-function-expander will automatically expand the callable object for you |
The g:expander_use_local_variables
is basically for convenience.
Say you have a block of text like this:
def some_function(text, items=None):
pass
items = ['foo', 'bar']
some_function(|x|)
Personally, if I write a variable to be the same name as a parameter of a function, it's because I want to use that variable in the function.
So instead of some_function(|x|)
expanding to some_function(text, items=None)
,
I'd rather it use items=items
, instead.
let g:expander_use_local_variables = 0
:
def some_function(text, items=None):
pass
items = ['foo', 'bar']
some_function(text, items=None)
let g:expander_use_local_variables = 1
: (Default)
def some_function(text, items=None):
pass
items = ['foo', 'bar']
some_function(text, items=items)
Nice, right? If you name your variables based on the functions which will use them, then vim-python-function-expander will actually end up writing all of your parameters for you. Just expand, maybe trim it, and then move on to the next task.
vim-python-function-expander uses jedi, UltiSnips, and astroid to work.
jedi is a fantastic static-analysis library. As long your module's contents are importable, jedi can usually find the definition of your object and its call signature.
vim-python-function-expander then takes jedi's call signature, which
could be [foo, bar, bazz=8]
and then converts into an UltiSnips-friendly
string like "${1:foo}, ${2:bar}, bazz=${3:8}"
. That string gets sent to UltiSnips
as an anonymous snippet.
UltiSnips then "expands" the snippet at the cursor's position and voila,
an automatic call signature is created.
astroid is used if you have
g:expander_use_local_variables
set to 1
. It is what is used to check
which variables you have already defined in your file and inserts them into the
call signature. It also is responsible for trimming the expanded parameters.
See Auto-Trimmer for details about trimming.