64

给定一个不断重复以下内容的 python 文件:

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

我想四处走动并使用熟悉的 vim 动作编辑此文件。例如,使用 (, ), [[, ]], {, } 或使用 di} 之类的命令删除/拉取/更改文本。

在其他语言(如 C++、Java、C# 等)中,花括号比比皆是,因此使用 di} 之类的动作可以轻松找到匹配的花括号并作用于该块。事实上,如果我在上述文本的 'b' 字符上并在 vim 中执行 di),它会成功删除两个括号之间的文本。

我认为问题在于python对代码块的检测。使用 (, ), [[, ]], {, or } 作为动作几乎都做同样的事情,带你到开始(在 def 行之上或之上)或结束(在函数的最后一行之后)功能。据我所知,没有办法轻松地告诉 vim“选择这个缩进块的所有内容”。在上面的示例中,我想在 if 行的“i”中打开,输入 di} 并让它删除整个 if 块(到此特定函数的末尾)。

我确信应该可以告诉 vim 在缩进的基础上进行这样的动作(好吧,也许不是那个特定的动作,而是一些用户定义的动作)。关于如何做到这一点的任何想法?

4

4 回答 4

52

方括号映射[[, ]], [m,]m和类似的

$VIMRUNTIME/ftplugin/python.vimnow (2018) 重新映射记录在python 语言下:h ]]的所有内置映射。:h ]m映射是:

]] 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

以下带有注释的示例源代码说明了不同的映射

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

在提交abd468ed0 (2016-09-08)、01164a6546b4 (2017-11-02) 和 7f2e9d7c9cd (2017-11-11)中添加和改进了映射。

如果您还没有此文件的新版本,您可以下载并将其放入~/.vim/ftplugin/python.vim. 此文件夹优先于$VIMRUNTIME/ftplugin.

在将这些映射添加到 之前,已经有提供、、和$VIMRUNTIME的插件。此外还定义了文本对象、、和:python-mode[[]][M]Mpython-modeaCiCaMiM

插件python 模式

这个 vim 插件提供类似于内置的动作:

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)
==========  ============================

插件Pythonsense

这个插件提供了类似的动作,但稍作修改:

常用的 Vim 8.0“类”运动(“]]”、“[[”等),查找从第一列开始的块,无论这些是类还是功能块,而它的方法/功能运动(“[m”、“]m”等)在任何缩进处查找所有块,无论这些块是类块还是功能块。相比之下,“Pythonsense”类运动致力于查找所有且仅类定义,而不管其缩进级别如何,而其方法/函数运动则致力于查找所有且仅方法/函数定义,而与它们的缩进级别无关。

所有详细信息和示例都在https://github.com/jeetsukumaran/vim-pythonsense#stock-vim-vs-pythonsense-motions中给出。此外,该插件还定义了文本对象ic/ac(类)、if/af(函数)、id/ad(文档字符串)。

有关 python 文本对象的讨论,请参阅通过 VIM 选择 Python 函数的最快方法是什么?.

于 2015-02-02T18:44:46.663 回答
21

蟒蛇.vim

使浏览 python 代码块变得更加容易。

捷径:

  • ]t -- 跳转到块的开头
  • ]e -- 跳转到块尾
  • ]v -- 选择(视觉线模式)块
  • ]< -- 向左移动方块
  • ]> -- 向右移动方块
  • ]# -- 评论选择
  • ]u -- 取消注释选择
  • ]c -- 选择当前/上一课
  • ]d -- 选择当前/上一个功能
  • ]<up> -- 跳转到具有相同/更低缩进的上一行
  • ]<down>-- 跳到具有相同/更低缩进的下一行

python_match.vim

扩展%

  • % - 循环通过 if/elif/else、try/except/catch、for/continue/break
  • g%- 移动对面%
  • [%- 移动到当前代码块的开头
  • ]%- 移动到当前代码块的末尾

上述所有动作都适用于正常、视觉和操作员挂起模式,因此:

  • d]% - 删除直到当前块结束
  • v]%d- 应该做同样的事情,通过可视模式,以便您可以看到正在删除的内容
  • V]%d- 上面,但有行选择
于 2009-09-08T13:56:12.580 回答
6

移动缩进块非常容易set foldmethod=indent。例如,如果您在def main():以下代码段中的行:

def main():
+-- 35 lines: gps.init()-----------------------------------------------------

if __name__ == "__main__": main()

然后dj获取整个主要功能,可以将其粘贴到其他地方。

于 2009-05-22T15:45:11.193 回答
0

为了解决您的最后一段,以下脚本定义了一个新的“缩进”文本对象,您可以对其执行操作。例如,dii删除与光标所在行同级缩进的所有内容。

有关更多信息,请参阅插件的文档:http: //www.vim.org/scripts/script.php? script_id=3037

于 2015-08-18T12:32:14.940 回答