More efficient movements editing python files in vim


Question

Given a python file with the following repeated endlessly:

def myFunction(a, b, c):
    if a:
        print b
    elif c:
        print 'hello'

I'd like to move around and edit this file using familiar vim movements. For instance, using (, ), [[, ]], {, } or deleting/yanking/changing text using commands like di}.

In other languages (like C++, Java, C#, etc) you've got curly brackets abound, so using a movement like di} can easily find a matching curly brace and act on that block. And in fact if I am on the 'b' character on the above text and do a di) in vim, it successfully deletes the text between the two parens.

The issue is in python's detection of code blocks, I think. Using (, ), [[, ]], {, or } as movements all pretty much do the same thing, bringing you to the start (above or on the def line) or end (after the last line of the function) of the function. And there is no way, as far as I know, to easily tell vim "select everything for this indentation block." In the above example, I'd like to be on in 'i' of the if line, type di} and have it delete the entire if block (to the end of this particular function).

I'm sure it should be possible to tell vim to operate on an indentation basis for such movements (well, maybe not that particular movement, but some user defined action). Any thoughts on how to accomplish this?

1
49
5/22/2009 2:25:37 AM

Square Bracket Mappings [[, ]], [m, ]m and similar

$VIMRUNTIME/ftplugin/python.vim now (2018) remaps all builtin mappings documented under :h ]] and :h ]m for the python language. The mappings are:

]] Jump forward to begin of next toplevel
[[ Jump backwards to begin of current toplevel (if already there, previous toplevel)
]m Jump forward to begin of next method/scope
[m Jump backwords to begin of previous method/scope

][ Jump forward to end of current toplevel
[] Jump backward to end of previous of toplevel
]M Jump forward to end of current method/scope
[M Jump backward to end of previous method/scope

Following example source code with comments illustrates the different mappings

class Mapping:                              # [[[[
    def __init__(self, iterable):
        pass

    def update(self, iterable):
        pass

    __update = update                       # []

class Reverse:                              # [[ or [m[m
    def __init__(self, data):               # [m
        self.data = data
        self.index = len(data)              # [M

    def __iter__(self):                     # <--- CURSOR
        return self                         # ]M

    def __next__(self):                     # ]m
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]        # ][

class MappingSubclass(Mapping):             # ]] or ]m]m

    def update(self, keys, values):
        pass

The mappings have been added and improved in the commits abd468ed0 (2016-09-08), 01164a6546b4 (2017-11-02), and 7f2e9d7c9cd (2017-11-11).

If you do not have the new version of this file yet, you can download it and put it into ~/.vim/ftplugin/python.vim. This folder takes precedence before $VIMRUNTIME/ftplugin.

Before these mappings have been added to $VIMRUNTIME, there has been the plugin python-mode which provides [[, ]], [M, and ]M. In addition python-mode also defines the text objects aC, iC, aM, and iM:

Plugin python-mode

This vim plugin provides motions similar to built-in ones:

2.4 Vim motion ~
                                                                *pymode-motion*

Support Vim motion (See |operator|) for python objects (such as functions,
class and methods).

`C` — means class
`M` — means method or function
                                                            *pymode-motion-keys*

==========  ============================
Key         Command (modes)
==========  ============================
[[          Jump to previous class or function (normal, visual, operator)
]]          Jump to next class or function  (normal, visual, operator)
[M          Jump to previous class or method (normal, visual, operator)
]M          Jump to next class or method (normal, visual, operator)
aC          Select a class. Ex: vaC, daC, yaC, caC (normal, operator)
iC          Select inner class. Ex: viC, diC, yiC, ciC (normal, operator)
aM          Select a function or method. Ex: vaM, daM, yaM, caM (normal, operator)
iM          Select inner func. or method. Ex: viM, diM, yiM, ciM (normal, operator)
==========  ============================

Plugin Pythonsense

This plugin provides similar motions but slightly modified:

The stock Vim 8.0 "class" motions ("]]", "[[", etc.), find blocks that begin at the first column, regardless of whether or not these are class or function blocks, while its method/function motions ("[m", "]m", etc.) find all blocks at any indent regardless of whether or not these are class or function blocks. In contrast, "Pythonsense" class motions work on finding all and only class definitions, regardless of their indent level, while its method/function motions work on finding all and only method/function definitions, regardless of their indent level.

All details and examples are given at https://github.com/jeetsukumaran/vim-pythonsense#stock-vim-vs-pythonsense-motions. In addition, this plugin defines the text objects ic/ac (class), if/af (function), id/ad (docstring).

For a discussion about textobjects for python see what's the fastest way to select a function of Python via VIM?.

28
10/27/2018 11:17:54 AM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon